We are all familiar with collection types.
Array, probably, the most common way to represent collection of items. We can easily iterate through by using
Another Swift collections representations, like
Set and others has one important thing in common: all of them are adopting
SequenceType protocol. We can create custom sequences for very wide range of purposes. It can be finite or inifinite sequence. For instance, we may need the ‘powers of 2’ sequence or similar.
SequenceTypeis a type, that can be iterated with a
SequenceType protocol has two associated types and a bunch of extremely useful methods for getting subsequences, iterating and your lovely
generate() -> Self.Generator method returns a generator over the elements of this sequence. Where
Generator is a type that provides the sequence’s iteration interface and encapsulates its iteration state.
GeneratorType is a simple protocol, which contains one associated type and one method -
Element is a type of an element generated by
next() returns an element if it exists, otherwise returns
The most convenient way of sequences is the generation of some famous math function like Fibonaci sequence or Powers of 2 sequence. I want to demonstrate Sequences and Generators power by creating some convenience methods for
NSDateare complex classes (or class clusters). Working with them, you need to take in concideration a lot of boilerplates, like time zone calculations, device locale and other important calculations. This article omits most of them. The purpose of it is Generators and sequences demonstration. Samples may be far-fetched.
Problem. Spanish lessons schedule
Let’s imagine, that we want to learn the new language. Spanish, for example. Your professor told you, that you will have one lesson each
N days starting from today. But the bad thing – your professor doesn’t want to work on Sundays. So if the lesson is on Sunday, it will be rescheduled to the next day. We want to receive the schedule –
Lets start from adding some convenience functions to
First of all, we will extend
calendarUnit(:) function. This function returns
NSDateComponents object depending on given
NSCalendarUnit. For the sake of convenience, we add
days var (that’s enough for our example, but you can add the same for all the calendar units you need).
Next we will write small
NSDate extension. For our convenience we will wrap
NSDate to be able to get the value of the needed
Then we define function
+ to have ability to add date components to our
Now we are able to perform calculation like this:
Our generator will look like this:
As you see in the code sample above, in some point our generator returns
nil. This is a very important moment! If you remove
nil termination, generator will continue to produce values while your computer has free memory.
Another important moment is, if you try to iterate through
dg one more time, it will not work as expected, because the instance of the generator is already exhausted.
DateGenerator to build a sequence on it.
As you see, sequence code is very simple and understandable. Actually, our Spanish schedule problem is solved :)
It’s not always needed to write your own generator. Apple guys are smart, and for the most cases you can use AnyGenerator. Rewrited with
AnyGenerator, our sequence will look like this:
Remember, we were afraid to remove
nil termination? This is the time to do it:
If you are using a playground, then you can see an infinite loop right after you hit Cmd+S shortcut. No worries, we can get needed amount of elements from the infinite sequence:
One of the key benefit of infinite sequences is ability to modify all it’s elements according to the rule. For instance, i want first 10 dates of our infinite sequence, but I hate Mondays. So I want to throw Mondays away:
Surprizingly, but this approach will not work, because we have infinite sequence.
LazySequenceType is the same as
SequenceType, with the key difference, that the elements of the result function, such as
filter, e. t. c. are computed on-demand as the result is used. To make sequence lazy use the
lazy property of the sequence:
Voila! We have finite dates sequence without Mondays.
GeneratorType are one of the most used protocols (even if you don’t see it). It is also correct and elegant solution for dealing with difficult data collections generating and iterating.
Where to go from here?
Check official Apple documentation for more GeneratorType, SequenceType and AnyGenerator info. Another good explanations of sequences and generators you can find in “Functional Swift” book by Chris Eindhoff.