InfiniteIterator in Swift

Earlier this week a designer came to me with a new design for the app I’m currently working on. He had designed a more interesting article-feed page layout.

The layout contained a header element, followed by 5 cells in various positions. The designer then requested that the layout repeat itself (minus the header) as long as there is more content to display.

Iterator

So at this point I knew I wanted to use a UICollectionViewLayout – because this gives us a nice abstraction from the underlying view and data.

I also decided to implement a separate type that would be responsible for calculating the frame of each cell in the layout.

public struct Layout {
    public func frame(for element: Element, in bounds: CGRect) -> CGRect
}

What is an Iterator?

I had been wanting to write my own Swift Iterator for some time now, so decided this was the best time to do so.

An Iterator is basically just a type that can iterate over some elements. Those elements could come from an Array, Set, Dictionary or some other Collection type.

For example, an IndexingIterator basically iterates over the indexes in a collection.

In Swift 4 the only requirement for defining your own Iterator is to conform to IteratorProtocol as well as defining a single function next() – which is responsible for returning the next element.

InfiniteIterator

What I decided to build was something I’ve called an InfiniteIterator which basically iterates over the elements of a collection, but when it reaches the end, it starts from the beginning again – infinitely!

public struct InfiniteIterator<Base: Collection>: IteratorProtocol {
    public mutating func next() -> Base.Iterator.Element? {
        // see playground for full source
    }    
}

Using this approach, I was able to simply iterate over the indexPaths for the items in my UICollectionViewLayout, grab the next frame in my layout and then assign that to the attributes.frame property.

public final class ArticleLayout: UICollectionViewLayout {
    public override func prepare() {
        // ...
        var frames = InfiniteIterator(collection: layout.frame(for: element, in: collectionView.bounds))
        // ...
        for section in 0..<collectionView.numberOfSections {
            for item in 0..<collectionView.numberOfItems(inSection: section) {
                guard let frame = frames.next() else { fatalError() }
                let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
                attributes.frame = frame
            }
        }
    }
}

Summary

I'm really pleased with the result. I was able to define the primary pattern of my layout, and then simply iterate over the elements of that layout to generate my feed.

Iterators are very powerful abstractions that provide much more powerful ways of stepping through our collections.

Its unlikely that you'll ever need to create one yourself since the Swift Standard Library provides more than enough for daily use.

However, if you're looking for an exercise how about writing an iterator that returns every 2nd element from a collection :)

If you want to share your own creations with me you can find me on Twitter as @shaps or post in the comments.


If you liked this post or want to discuss more, leave a comment below or find me on Twitter