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.

A Lexer in Swift

This is a multi-post series covering the definition, example code and basic error handling/recovery of a Lexer, Parser and AST written in Swift (although concepts can be applied to any language).

These posts are targeted at the beginner–as such I will only cover the basics for getting started. This post will focus entirely on the Lexer.

I’ll also include a Swift Playground at the bottom of each post if you want to try it out for yourself. *Requires Xcode 9 (Swift 4).

Why build a Lexer?

I wanted to write a Lexer/Parser to improve my skillset. I wanted to better understand the definitions of the various components, the responsibilities of each and more importantly why I’d want to write one in the first place.

I had trouble finding simple examples that just went over the basics, so that’s what I’ve tried to do here. Hopefully you’ll find this useful as well.

What I’ll cover

This post is for beginners, I’ll discuss the various components of a Lexer as well as its responsibilities. I’ll also briefly discuss performance and error handling.

As I mentioned above this article is targeted at beginners, so I’m going  to demonstrate building a Lexer for parsing arithmetic operations.

Definitions

Code Point
A code point defines a single unicode scalar value. This is a complex subject so for the purposes of this article, you can consider a code point equivalent to a character.

Throughout this article I will use the terms Character and Code Point interchangeably.

Token
A token is essentially a component of our grammar. A token generally represents 1 or more code points.

Lets see how the equation will be tokenised.


tokens.jpg

The responsibility of a Lexer is to generate a tokenized representation of the source string. 

Characters vs Code Points

Typically when we talk about the components of a String, we think of it being made up of Characters. However there is another level of detail here. Characters can be made up of 1 or more Code Points which are essentially UnicodeScalar values.

For the purposes of this article however these two types are equal – as such I will use the term Characters however all example code will work on UnicodeScalar‘s. 

Tokens

A Lexer is responsible for breaking a string into smaller components, called Token’s. Lets look at a simple example:

5 + 23 * 3 = 74

Lets start by defining the components of this expression. For the purposes of this article, we’ll only consider Integer values and 4 simple arithmetic operators only.

  1. Digits (0-9)
  2. Operator (+, -, *, /)
  3. Equality (=)
  4. Space

An arithmetic equation contains 2 expressions, left and right separated by an equality character. For the purposes of our Lexer, this isn’t really relevant however. We simply care about the ‘components’ that make up our equation. 

Omissions

To keep things simple I’ve omitted a lot of details for truly parsing any function, i.e. parentheses, negative/floating-point/exponential numbers, etc.. I’ll leave those as an exercise for the reader.

Whitespace

If you plan to do any form of Linting you’ll require whitespace tokens, however if you plan on writing a compiler to validate the equation then whitespace is obviously not important.

Tokenizer

Now that we’ve defined our possible tokens, lets define our Lexer class that will consume them.

public final class Lexer {
    func tokenize(source: String) -> [TokenType] {
        var tokens: [TokenType] = []
        let chars = source.unicodeScalars 

        while let token = chars.consumeToken() {
            tokens.append(token)
        }

        return tokens
    }
}

Notice the helper function: chars.consumeToken()
Lets define that now.

extension UnicodeScalarView {
    mutating func consumeToken() -> Token? {
        return consumeSpace()
            ?? consumeDigit()
            ?? consumeOperator()
            ?? consumeEquals()
    }
}

Remember each consumer is responsible for returning either a single Token or nil. We are considered done when no more tokens are returned. i.e all consumers return nil.

Space Consumer

For the purposes of this post I’ll demonstrate the first consumer, however you can checkout the Playground for the full implementation.

The following represents a simple white-space consumer.

extension UnicodeScalarView {
    mutating func consumeSpace() -> Token? {
        return consumeCharacters(where: {
            $0 == UnicodeScalar(" ")
        }).map { .space($0.characters.count) }
    }
}

Basically this function will attempt to consume a space character. If its successful, it will return a token with the number of spaces found. Otherwise it will return nil and the next consumer will be run.

Result

So lets run our equation through our Tokeniser:

let source = "5 + 23 * 3 = 74"
let tokenizer = Tokenizer()
let tokens = tokenizer.parse(source)
dump(tokens)

Which will output the following:

▿ .number: "5"
▿ .space 1
▿ .operator: "+"
▿ .space: 1
▿ .number: "23"
▿ .space: 1
▿ .operator: "*"
▿ .space: 1
▿ .number: "3"
▿ .space: 1
▿ .operator: "="
▿ .space 1
▿ .number: "74"

So there we have it, a simple Lexer for tokenizing an equation from a string.

Error Handling

There are several types of failures that can occur.

Parse Error

The first is a parse error, where we couldn’t reach the end of the file but came across a character we couldn’t parse. In the tokeniser above we could simply fail and return a generic error, perhaps with the last position where the failure occurred.

In my own tokeniser I found that I could simply recover. The best approach I found was to change my loop to iterate while !eof (end-of-file). When I came across a character that couldn’t be parsed, I would simply consume it into an .error(Range<String.Index>) token and attempt to continue.

Unexpected Token

Using our example equation, an unexpected token would be something like sequential operators with no digits in-between.

4 + / 5 = 9

This could also be considered a parse error, however the difference here is that out Tokeniser won’t fail because we can parse that into tokens. This is where our Parser comes into play, but we’ll cover that in the next post.

Performance

When I initially wrote the Lexer I kept it simple (similar to the example code in this post) and made all of my tokens an enum with an associated String value.

We’re working with UnicodeScalarView – which is basically just a cursor into the string, so walking through the characters has almost zero-cost. However every time I parsed a character, I’d make a copy into a String and store it in a token. 

A better approach is to consider your token data and store it more appropriately. The following would be much more performant:

enum Token {
    case digit(Int)
    case space(Int) // number of spaces
    case addition
    case subtraction
    case multiplication
    case division
    case equals
}

Our simple equation Lexer probably wouldn’t see much benefit from this considering the small amount of characters we would be parsing, even in extreme cases. However when you’re parsing thousands of lines or more, these kinds of refactors can be hugely beneficial.

For reference, my Tokenizer went from 40ms to 16ms for a 1000 line file by making the simple change suggested above.

Conclusion

Writing a lexer can be a daunting and time-consuming task however there’s a lot to be gained by doing so. 

  • Improve understanding of Lexers/Parsers and in-part Compilers
  • Improve your understanding of Unicode constructs
  • Improve your performance tuning skills – you’ll need it!

If you have any questions or just want to chat, you can find me on Twitter @shaps.

Behaviour Composition with Storyboard’s

Applications are made up of multiple interactions and behaviours. Often times, our view controllers and views end up bloated because of the shear number of interactions that can occur. Furthermore, this makes testing our behaviours even more complicated since they are tied to our view layers.

If you just want to jump straight into the source, you can find a demo project @ github.com

The Deck

Here’s a deck that better explains the concept. Don’t forget to checkout the code and please share 👍

Advanced Gesture Recognisers

Through this article I’m going to show you how to use a UIPanGestureRecognizer to create a marquee selection tool that you can use in any of your UIView’s.

Gestures

UIGestureRecogniser’s are a really powerful way of working with touch events in iOS. They allow us to handle taps, pans, pinches and more. Through a simple state-driven API we can easily use them to detect lots of types of interactions in our apps.

Marquee Selection



Finder

Similar to what you would find in Finder or another file browser.

Recently I came across a feature I needed to build. Basically I needed to provide a marquee selection tool like you might see in Finder for selecting files and folders.

UIPanGestueRecognizer seemed like a perfect fit for the job since it provides location data while the you move your finger across the view. So I added one to my view and proceeded to write some code for handling the marquee itself.

Typical Solution

So I started off by checking the recognizer state and recording the initial location when state == .began

I then used location(in view:) while the gesture’s state == .changed — finally creating a rectangle between the two points.

At this point I had a working marquee tool but I was drawing the rectangle using draw(rect:) of the gesture.view, which wasn’t ideal, especially because it meant I couldn’t draw on ‘top’ of the subviews.

So I decided to add a view instead based on the gesture’s state.

.began – add the marqueeView to the source view
.changed – set the frame of the selection view
.ended – remove the selection view from the source view

At this point however I realised that this solution wasn’t ideal since I was now tied to this specific implementation of UIView. Furthermore, if I wanted to provide selection to something like a UICollectionView then I would have to copy/paste a lof of code.

Alternative Solution

The solution I came up with was to move the marqueeViewinto the gesture itself. In hindsight this seemed obvious. The gesture has everything I need to provide a selection rectangle. Its state-driven, provides the location of the touch events during a pan, and even provides me with the source view.

All I had to do was listen for the various state changes and insert/remove my marqueeView appropriately. Lets checkout an example.

import UIKit.UIGestureRecognizerSubclass

public final class MarqueeGestureRecognizer: UIPanGestureRecognizer {
    public private(set) var initialLocation: CGPoint = .zero
    public private(set) var selectionRect: CGRect = .zero
    public var tintColor: UIColor = .yellow
    public var zPosition: Int = 0

    public override init(target: Any?, action: Selector?) {
        super.init(target: target, action: action)
        addTarget(self, action: #selector(handleGesture(gesture:)))
    }

    private var marqueeView: UIView? {
        didSet {
            marqueeView?.backgroundColor = tintColor.withAlphaComponent(0.1)
            marqueeView?.layer.borderColor = tintColor.cgColor
            marqueeView?.layer.borderWidth = 1
            marqueeView?.layer.zPosition = CGFloat(zPosition)
        }
    }

    @objc private func handleGesture(gesture: MarqueeGestureRecognizer) {
        guard let view = gesture.view else { return }

        let currentLocation = gesture.location(in: view)
        selectionRect = CGRectReversible.rect(from: initialLocation, to: currentLocation)

        switch gesture.state {
        case .began:
            let marqueeView = UIView()
            view.insertSubview(marqueeView, at: zPosition)
            self.marqueeView = marqueeView
            initialLocation = currentLocation
        case .changed:
            marqueeView?.frame = selectionRect
        default:
            initialLocation = .zero
            selectionRect = .zero

            marqueeView?.removeFromSuperview()
            marqueeView = nil
        }
    } 
}

For the full code, you can download the Playground on GitHub:

Summary

Subclassing a UIGestureRecognizer and adding behaviour to it has a lot of advantages:

  • You can easily composite this into any view
  • You can add advanced behaviour to your gesture; e.g.
  • Hold down a second finger to constrain aspect ratio
  • The marqueeView’s lifecycle is bound to the state of the gesture; i.e.
  • no need to manage it from your view controller, etc…
  • Gesture’s are state-driven by default, which makes them great to work with.

Have a cool idea for another gesture recognizer? Maybe you’ve done something similar before? I’d love to hear about it.

Generic Delegate’s in Swift

A common pattern in cocoa development is the use of the delegate pattern. Most commonly used as a callback mechanism.

In Swift however sometimes we would like to use this pattern along with a generic implementation of our type. First, lets look at the problem.

The Problem

A typical approach would look like this:

struct Item { }

protocol ItemDelegate: class {
    func didSelect(item: Item)
}

final class ItemController {
    weak var delegate: ItemDelegate?
}

This works great while Item is a concrete type, but what if we wanted to make Item generic?

protocol Item { }
struct MyItem: Item { }

final class ItemController<ItemType: Item> {
    weak var delegate: ItemDelegate?
}

Well we can simply make our delegate generic as well right?

protocol ItemDelegate: class {
    func didSelect<ItemType: Item>(item: ItemType)
}

Well actually this isn’t right. To see the problem lets check out the callsite:

let controller = ItemController<MyItem>()
func didSelect<ItemType>(item: ItemType) where ItemType : Item {
    print("\(item)")
}

Specifically where ItemType : Item. Item is our protocol and not our concrete type MyItem. So even though we’ve successfully constrained our controller to a specific type, our delegate is much less specific.

The Solution

What we really want to do is define an associatedtype on our delegate.

protocol ItemDelegate {
    associatedtype ItemType: Item
    func didSelect(item: ItemType)
}

The problem is that now we have a generic constraint on our ItemDelegate. The solution is actually quite simple. Instead of constraining our ItemController to a specific Item, instead constrain it to a specific ItemDelegate.

Our final solution would look like the following:

protocol ItemDelegate: class {
    associatedtype ItemType: Item
    func didSelect(item: ItemType)
}

final class ItemController<Delegate: ItemDelegate> {
    weak var delegate: Delegate?
    func addItem(item: Delegate.ItemType)
}

Now if we look at our callsite:

let controller = ItemController<MyItem>()
func didSelect(item: MyItem) {
    print("\(item.name)")
}

Recap

By moving the generic constraint to the delegate we can now safely define an instance of ItemController and ensure our delegate callbacks are type-safe to the same concrete instance.

This is a fairly simple approach but makes working with generic delegate’s much simpler and much safer.

Introducing Peek 2.0

Version
License
Language
Platform

Peek is an open source library that lets you easily check your application against your user interface’s specification guide(s). Peek can be used by engineers, designers & testers, allowing developers to spend more time on code and less time checking that fonts, colors and layout are pixel perfect.

How does it work?

Tap your volume key(s) to activate/deactivate Peek.

Then tap, or drag your finger across the screen to select a component and see its layout information.

Double-tap anywhere on the screen to bring up the Peek Inspectors. Here peek will show you contextual information about the view you’re inspecting. For example, a label will show information such as font and textColor, whereas an image might show information about its size or scaling mode.

You can also tap and hold on any property to copy it to your pasteboard. More features coming soon regarding this — which will allow you to report issues back to your dev(s).

Peek currently supports a single overlay mode, but more are coming soon – including an overlay that allows you to see measures between components!

How do I get started?

Peek was designed to be extremely easy to use.

If you’re a designer, send a link to this page to your dev(s) 😁

For developers, simply use CocoaPods (alternativel you can simply drag the files into your project.

pod 'Peek'

Then add a single line to your App Delegate:

window?.peek.enabled = true

Optionally, I’d suggest adding the DEBUG Swift compiler flag and changing the code to:

#if DEBUG
  window?.peek.enabled = true
#endif

You can also provide options when enabling Peek:

window?.peek.enableWithOptions { options in
  // Peek will require a shake on the device and simulator
  options.activationMode = .shake

  // Container views (UIView) will not be ignored
  // Note: this does not include system containers
  options.shouldIgnoreContainers = false
}

Now whenever you run your app, you can now activate/deactivate Peek by pressing one of the volume keys on your device 😉

Safety First

Peek is designed to be as safe as possible. Peek will never retain objects from your application. It will never use a background thread. Peek won’t even run unless you explicitly enable it!

Go ahead, take a Peek at your app now 🙂

What about using Peek from the simulator?

Since the volume keys are not available on the Simulator, we can use a shake gesture instead. Simply forward the motion events to Peek by adding the following code to your AppDelegate.swift:

override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?) {
  window?.peek.handleShake(motion)
}

Now you can press CMD+CTRL+Z (or use the Menu option) to activate/deactivate Peek from your Simulator.

Supported Platforms and Versions

Peek is tested and supported on iOS 8 and above. Its also iPhone and iPad supported, in all orientations. In fact, Peek will only rotate if your app can 😉

About Peek

  1. Peek only requires a single line of code to get started
  2. Peek is disabled by default, so just make sure to use #if DEBUG to prevent it from being included in your release binary
  3. No 3rd party code or libraries are used in Peek — all code is my own!
  4. Peek never interferes with your apps normal behavior, gestures or layout – and it NEVER retains an object from your application
  5. Peek supports all orientations and devices.

How does Peek work?

Peek scans all the views in your entire view hierarchy that is currently on the screen then overlays these views with layout information.

Peek then uses its filtering system to best determine which views you care about and those that you are not likely to be interested in.

For example, by default Peek will not show you many of Apple’s system components unless they are subclassed. A label however is a perfect exception to this, where you might not want to see all labels in a tab-bar but you do want to see the labels inside a cell.

Peek presents itself in its own window that sits directly on top of your own app’s user interface to ensure that it doesn’t interfere with normal functionality.

Peek also allows you to test all supported orientations on both iPhone and iPad.

Roadmap

There are a lot more features still to come, here’s a short preview I think are quite interesting:

  • Slack Integration (post issues to a Slack channel)
  • Image crop indicators
  • Auto Layout overlays