Understanding Collections Types in Swift — Part 3
In Part 1 of this series, we covered Arrays and Sets — two of the collection types in Swift. We hit the highlights and went over how they are similar and where they differ. If you didn’t read part 1, do that before reading this article to make sure you get the background on Arrays and Sets.
Swift Collections — Part 1 (Arrays and Sets) ¶
There are three collection types in the Swift language: Arrays, Sets…medium.com
In Part 2 of this series, we explored Set operations and Dictionaries as a collection type. You’ll want to read part 2 before covering today’s topic.
In Part 1 of this series, we covered Arrays and Sets — two of the collection types in Swift.medium.com
This article is going to cover how to code your classes and structs to take advantage of an underlying Collection types like Arrays, Sets, or Dictionaries.
Motivation & Problem
You can accomplish many tasks just using the built-in collection types. In fact, you might struggle to find a reason not to use one of the classes provided by Apple. However, there are times when an Array alone doesn’t store enough peripheral information to suite your needs. For example, you might be able to perform 90% of your tasks with a Dictionary, but you still need a secondary list or object to accomplish the remaining 10%. Wouldn’t it be better to find a solution that uses only one object over multiple? Let’s check out some possibilities.
There are many ways to tackle adding new functionality to existing classes and structs. All have merit in the right context. We will go over one way as a means to get you started. The goal is to think creatively about giving your classes and structs the power of a collection and the flexibility of additional features when needed. Here is our problem statement:
Build a Rolladex to hold my contacts. I want to be able to compare my contacts to yours, looking for similarities and differences. I should be able to add, remove, and edit contacts. I should also be able to search contacts by name to receive a filtered result set.
You might start by building a Person object to store the contact details. Next you create an array to hold the Person type and you’re done. Nice. Problem solved. But wait, could you create a better solution? After all, our current solution doesn’t address the filtering or comparison aspects of the problem. We would need to create additional methods to make our solution more complete. Complicating matters, we now have to determine who should own the methods. In the next sections below, I propose that we keep the Person object and create a custom collection object to hold our contacts. Our collection object will be a simple struct that contains a Set to hold our contacts.
Looking at the code below, you should notice that I created a Person struct that conforms to the Hashable protocol. Sets can only hold items that adhere to the Hashable protocol. This means our Person struct will ultimately need to be hashable.
Pretty straightforward code, right? True, but let me point out a couple subtleties that you might have glanced over.
- My implementation of the hashValue properties combines the structs properties into a string using String Interpolation and then accesses the hashValue of the resulting string. When creating a hashValue, the returned value has to be both reproducible and unique to the object. When two objects have the same hashValue, they are considered equal.
- All objects that conform to the Hashable protocol must also conform to the Equatable protocol. Therefore we need to implement the equality operator for our type. Notice that this function has global scope as required in Apple’s specs. We don’t have to implement the inequality operator since we get that one for free.
It’s time to address our collection concerns. While a Set could be the right choice in which to store our contacts, we need more control to add features to associate with our contact list.
Our code sample below now contains the struct PeopleCollection. It has a Set named people to hold a list of our Persons. We also add several helper functions to make accessing our people Set easier. I’ll leave it as an exercise for the reader to figure out how to hide the details of the people Set for additional security. After all, a consumer of this collection doesn’t need to directly access our underlying Set provided we have given them additional ways to expose the relevant information.
As with the Person code block, there are a couple things that you may have overlooked at first glance.
- We need to use the mutating keyword for the add and remove methods because those methods change the people Set. Since structs are value types, you need to opt in to the ability to change a value.
- Our retrieveSharedConnections method returns all of the shared contacts that two PeopleCollections contain. This could have been a daunting task. Imagine looping through two list multiple times to check whether a value in the first list is contained in the other. It’s not a problem for smalllist but could potentially be a larger issue as the contacts lists for each list grows. Fortunately, we can use the set operation intersect to do this in one line. If this wasn’t obvious to you, go back and read part 2 of the Swift Collections series.
For the keen observer, you may have noticed that my playground file shows formatted outputs for the Person and PeopleCollection objects. It turns out that this is very easy to accomplish, and you should definitely use this with your own code. The CustomStringConvertible protocol has a description property that you can modify for your use. You just need to return a suitable description of your object with the getter. Pretty cool! I can’t tell you how many times I have had to add print statements while trying to debug code to figure out what was in a particular variable. Those days are gone!
This is the end of our series on Swift Collections. I hope it was useful.
On a lighter note, I also wrote an article on why creating native apps is probably the best way to go in most of your mobile development endeavors. Read it and weigh in the discussion!
If your company only makes hybrid apps, you are going to lose in the end; it’s just a matter of time. Hybrid mobile…medium.com
Or check out my article on the common traits Rockstar developers possess.
I have spent over 15 years in software development. I have been an individual contributor, a technical lead, and have…medium.com
If you find this post helpful, please recommend it for others to read. You can visit me at www.gittielabs.com and subscribe to my RSS feed so that you won’t miss a post. I’m also putting together a video course to teach Swift development and could use your input on topics you feel would be helpful. Thanks for reading!