Sequence Hacking in Swift (III): Building Custom Sequences for Fun and Profit - Digital Leaves
post-template-default,single,single-post,postid-1998,single-format-standard,qode-social-login-1.0,qode-restaurant-1.0,ajax_fade,page_not_loaded,,select-theme-ver-4.1,wpb-js-composer js-comp-ver-5.2,vc_responsive

Sequence Hacking in Swift (III): Building Custom Sequences for Fun and Profit

Hi there! This is the third and final episode of the “Sequence Hacking in Swift” series. In the first article, we learned what a sequence was and how to use its basic functions (map, filter, reduce…). In the following post, we learned about extending sequences and performing custom operations on them. Today, we are going to focus on creating our own custom sequences.


The first question you may ask yourself when building a custom sequence is “why?”. Before actually implementing a custom sequence, ask yourself if the behavior you need can be obtained by using or extending one of the existing sequence types (like collection, array, set, etc…). Sometimes, that is enough, but other times, it may be really convenient to create your own. Some of the reasons might be:

  • Increased performance or special use case: you want to build a highly efficient sequence for a specific task, maybe using optimized algorithms for iterating through a series of elements (that might be inefficient if managed through a class API) or employing specific techniques to do the task faster or consuming less resources.
  • Reusability: you may want to build a custom sequence for a concrete task or series of tasks that you perform a lot in your applications. Sometimes, creating a custom sequence that encapsulates a concrete behavior can be a nice way of having a ready-to-add library for your projects. I certainly have several of those in my repertoire.
  • Specific requirements: you may need some specific requirements for concrete applications, like keeping the elements of a sequence in memory for efficiency, or retrieving/caching them beforehand and then iterating through them. You may need to free some resources after extracting a item from the iteration… there are lots of specific conditions that may need you to implement a custom sequence.
  • Legacy functionality: you may need to access legacy functions or functionality outside the scope of the modern Cocoa frameworks for Swift (i.e: old C-style cryptographic stuff, or old Carbon libraries) that need some specific treatment when iterating through the elements of the sequence.

Whatever the reason, once you decide that the right solution for you is creating your custom sequence, you need to understand how to implement the basic functionality of your custom class.

The Basics

You might recall from the previous article that a Sequence is basically an Iterator (a class following the IteratorProtocol protocol) with a makeIterator() function, an associated Iterator.Element type (that defines the type of elements that this Sequence contains) and a set of  associated functions like map, reduce, flatMap, filter, etc.

So in order to build a Sequence, we just need to build a class that implements this IteratorProtocol to act as the iterator for the elements of the sequence, and create the makeIterator() class. The iterator, in turn, is basically a “next()” function that retrieves the next element in the sequence, or nil if there are no more elements in it.

We can implement our custom Sequence with either a class or a struct. Usually a class is used, but it’s up to you to choose a struct if this entity will make more sense as a struct than as a class. Let’s start with a basic example to understand how this works, a simple “word iterator” that is a Sequence of characters (if that sounds familiar, it is because this is basically a Swift string. A Swift string is, actually, nothing more than a sequence of characters. This is probably a very dumb example, but will help you understand the basic concepts for creating your custom Sequences.

A basic word sequence

When building a custom sequence, it makes sense to think bottom-to-top, from the elements to the sequence. Think about the elements, its nature (type), how are they distributed in the sequence and how can I iterate from one to the other. If the sequence is finite, when exactly does it end?

Our iterator will start with a String, in the String.startIndex, and then iterate by advancing this index one by one:

Notice how we return nil when we get past the end index of the string. Notice also how, given that our Sequence is a String, our Iterator deals with Characters. This is defined by the exact nature of your Sequence. For instance, if you build a Sequence that represent the binary numbers (returing 2, 4, 8, 16, 32, etc), your IteratorProtocol subclass will return integers, so the Iterator.Element type will be Int.

Now, we can build our Sequence by returning an instance of WordIterator in our makeIterator() method:

Easy as pie, right? For such simple sequences, we can always build an inline class and return it in the makeIterator() method directly. So, we could get rid of the WordIterator class and just encapsulate all the functionality in a self-contained class:

Here, the AnyIterator<Character> is a “placeholder” iterator class that’s part of the basic Swift SDK, and uses generics to forward the “next()” method to the element type contained. So in this case, we just build a implicit String -> Character iterator that does exactly what our WordIterator did, and return a AnyIterator<Character> as the result of makeIterator() to clearly hint the compiler that we are returning an iterator containing characters from our String sequence.

Now, we can use our cool custom Sequence to iterate through any string, yay!

Hacking Sequences: the never ending emoji sequence.

Now it’s time to break the rules we have just learned to have some fun with sequences. If you think about it, there’s nowhere in the Sequence description or its protocol API specifying that a Sequence must be finite, so let’s take that approach to build a never-ending emoji sequence for fun.

For doing this, we’ll take advantage of the fact that we can encapsulate both the IteratorProtocol and the Sequence functionality in an entity that implements both. If we declare a class or struct as implementing Sequence and IteratorProtocol, we will just need to specify a “next()” method, and we won’t need to define the makeIterator() method: it will gladly return itself as a default behavior, due to Swift type inference and the way in which the method is defined in “Sequence”. Let’s see our EmojiSequence struct definition (yes, we are using a struct here to illustrate how you can use structs for custom Sequences when they are as simple as in this case).

The idea is simple, the “next()” method will call the randomEmojiIndex() method to generate a random string index, thus pointing to a random character of our emoji string with each call, and then we will just return the character pointed by this index.

The funny thing about this sequence is that it never ends (because next() never returns nil), so if you do something as simple as this:

Your application will enter an infinite loop. You can always set a safety variable, and return nil after a concrete (or random) number of emojis served, but then it won’t be that fun, now would it?

Where to go from here

In this final episode of the “Sequence Hacking in Swift”, we have learned how to implement our custom sequence types, either structs or classes. We also learned not to limit ourselves to the strict definition of a Sequence to get some fun results. Next, I want to write about generics in Swift and how to get the most of them. But that is another story for another day. Do you have any comments? Some funny sequences of your own you want to share with us? Let us know in the comments!

❤️ Did you enjoy this article?

If you found this content useful, consider giving some love back by making a small bitcoin, ethereum or bitcoin cash donation. Thank you!

BTC: 331u8dLejzfssKY3cXm1DPPvtaibaS4S9z

ETH: 0x994ECE4B48144f5541B34D5f15a3D671e51D7E05

BCH: 1KejtFCcrv7X2ZgovpLgs6pwgqDo1KmrmS

  • Alexander

    September 3, 2017 at 11:12 am Reply

    Great series. I dont quite understand the AnyIterator though. Why do you use it?

    And also, Ive never seen a return with a closure. You are basically returning a function, but its somehow connected to the anyIterator? I need to read more about that, whats it called?

    Im talking about the part thats:

    return AnyIterator { … }

    • Ignacio Nieto Carvajal

      September 3, 2017 at 4:50 pm Reply

      Hi there Alexander. Thanks, glad to know it was useful.
      Regarding your question, AnyIterator is a generic iterator that allows you to iterate through any given sequence.

      What I am returning in the function makeIterator is an instance of iterator. This is because AnyIterator has an initializer that accepts a closure for the “next()” method (that returns the next item in the sequence). Using closures as parameters for initializing objects is not usual, but this is one of the most interesting examples.

      You have more information about this amazing -if somewhat confusing class- here:

Post a Comment

Before you continue...

Hi there! I created the Digital Tips List, the newsletter for Swift and iOS developers, to share my knowledge with you.

It features exclusive weekly tutorials on Swift and iOS development, Swift code snippets and the Digital Tip of the week.

Besides, If you join the list you'll receive the eBook: "Your First iOS App", that will teach you how to build your first iOS App in less than an hour with no prior Swift or iOS knowledge.

I hate spam, and I promise I'll keep your email address safe.