Learn the iterator design pattern by using some custom sequences, conforming to the IteratorProtocol from the Swift standard library.
This time I'm going to focus on the iterator design pattern. The pattern is heavily used in the Swift standard library, there are protocols that will give you support if you need to create an iterator, but honestly: I've never implemented this pattern directly. 😅
The truth is that probably in 99% of the use cases you'll never have to deal with this pattern, because there is amazing support for iterators built-in directly into Swift. Always use sequences, arrays, dictionaries instead of directly implementing this pattern, but it's good to know how things are working under the hood, isn't it? 🙃
What is the iterator desin pattern?
As the name suggests, the pattern enables you to iterate over a collection of elements. Here is the definition from the gang of four book:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Long story short the iterator gives you an interface that will enable you to iterate over collections regardless of how they’re implemented in the background. Here is a quick example of the theory above using a string iterator.
As you can see there are two main protocols and a really simple implementation for both of them. Our
DataArray class now acts like a real array, the underlying elements can be iterated through using a loop. Let's ditch the theory and re-implement the example from above by using real Swift standard library components. 😉
Custom sequences in Swift
Swift has a built-in sequence protocol to help you creating iterators. Implementing your own sequence in Swift is all about hiding your underlying data structure by creating a custom iterator object. You just have to store the current index and return your next element according to that each time the next function gets called. 😛
So the Sequence protocol is a generic counterpart of our custom iterable protocol used in the first example. The IteratorProtocol is somewhat like the string iterator protocol used before, but more Swiftish and of course more generic.
So, this is great. Finally you know how to create a custom sequence. Which is good if you'd like to hide your data structure and provide a generic iterable interface. Imagine what would happen if you were about to start using a dictionary instead of an array for storing named emojis without an iterator that wraps them. 🤔
Now the thing is that there is one more super useful thing in the Swift standard library that I'd like to talk about. That's right, one abstraction level up and here we are:
Custom collections in Swift
Collections are one step beyond sequences. Elements inside of them can be accessed via subscript they also define both a startIndex and an endIndex, plus individual elements of a collection can be accessed multiple times. Sounds good? 👍
Sometimes it can be useful to create a custom collection type. For example if you'd like to eliminate optional values. Imagine a categorized favorite mechanism, for every category you'd have an array of favorites, so you'd have to deal with empty and non-existing cases. With a custom collection you could hide that extra code inside your custom data structure and provide a clean interface for the rest of your app. 😍
I know, this is a really dumb example, but it demonstrates why collections are more advanced compared to pure sequences. Also in the links below there are great demos of well written collections. Feel free to learn more about these super protocols and custom data types hidden (not so deep) inside the Swift standard library. 🤐