Scheduling Services

A micro-post about a micro-framework. Schedule (possibly repeating) events for some time in the future, along with restoration support. An NSNotification-based scheduling service in Swift.

Requirements

  • Schedule a request
  • Cancel a request
  • Restore all requests upon app-launch
  • Pause/resume all requests

Essentially I wanted to remove the knowledge/management of a timer. Obviously the implementation would need to handle this, but I wanted to build an abstraction on top of this that would support all of my requirements, while providing a simple/clean API.

Scheduling Service

The result is a lightweight micro-framework – SchedulingService.

// schedule a request
let request = service.schedule(date: Date().addingTimeInterval(5))

// cancel the request
service.cancel(request)

// schedule an NSNotification
service.schedule(date: Date().addingTimeInterval(20), 
         notification: .CountdownDidUpdate)

Codable

I also wanted to be able to save/restore all scheduled events so that I wouldn’t need to restore them manually upon launch.

// decodes or makes a new Service
let store = SchedulingServiceStore(service: nil)

// encodes the current service
store.service.save()

Super simple, single file micro-framwork.

View Descriptors

When building our apps, its fairly well known that passage models into our views leads to bad things. I don’t want to say its a black and white POV but its rarely a good idea or even necessary to begin with.

An often recommended approach is to use a ViewModel or Extension to add properties that provide UI representations of our models data. I’d like to suggest a slight alternative that testable and scalable even across large projects.

Example

Lets say we have a simple type to represent a Product. We might have a Model similar to the following:

struct Product {
    let title: String
    let price: Decimal
}

A product can have a title and a price. We don’t want to lose our underlying types, but at some point we need to present the price to the user in their local currency.

View Model

One solution to this problem is to introduce a View Model.

struct ProductViewModel {
    let title: String
    let price: String
}

While this approach is highly testable and allows you to abstract away the presence of the original Model, it also comes with some caveats.

  1. The name of the ViewModel is tightly coupled to the original Model itself, and so refactoring could be painful to keep these names in sync. This is the #1 issue I’ve faced myself.
  2. Often leads to some duplication where the value can be mapped directly.

Swift Extension

Another solution is to simply extend the Model itself.

extension Product {
    var priceString: String? {
        let decimal = NSDecimalNumber(decimal: product.price)
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter.string(from: decimal)
    }
}

While this approach isn’t inherently bad – as long as you keep it immutable – one of the biggest issues arises when you start naming things. You can already see that we now have a price as well as a priceString variable to make it clear that the latter returns a string representation of the price.

Descriptors

An alternative approach I’ve come up with that I’ve battle tested and had proven success across even large projects, is something I call View Descriptors.

Its basically a merge of the above concepts. Where the Descriptor is a dedicated type that’s added to your model type through an extension.

extension Product {
    struct Descriptor {
        private let product: Product

        init(product: Product) {
            self.product = product
        }
    }

    var descriptor: Descriptor {
        return Descriptor(product: self)
    }
}

Now we have a dedicated type that can better describe our model to the UI. Lets add a currency specific price value to our descriptor.

extension Product.Descriptor {
    var price: String? {
        let decimal = NSDecimalNumber(decimal: product.price)
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter.string(from: decimal)
    }
}

We can now access our model’s values as such:

let product = Product(title: "iPhone X", price: 1_000)
product.price
product.descriptor.price

// prints
// 1000
// £1,000.00

Conclusion

Compared to the approaches above, I feel this solution provides the best of both worlds, with almost none of the caveats.

  1. No need to sync type names (i.e. Product ‣ ProductVM)
  2. No unnecessary duplication
  3. API is much more descriptive – allowing variable name reuse
  4. Still highly testable API
  5. Really easy to migrate/refactor existing models in an incremental fashion

My favourite thing about this solution is that the model and the descriptors are implicitly tied together, while still providing unique interfaces for their specific domain.

Peek… behind the curtains

Update: new statistics added below

So you spent a long time building something and you think its worthy. You feel strongly that you’ve built something everyone can benefit from. So how do you improve awareness, generate usage and build a community around your product?

Well I’m not going to lie to you. I didn’t have a plan, so [Peek] was ready 2 weeks beforehand but I didn’t want to release it unless I could do it right.

So I had to do some research to see how the pros did it. I had to make a plan and I had to learn how to edit a video!

Contents

  1. The plan
  2. The video
  3. The README
  4. The product page
  5. The blog
  6. Social Networking
  7. The release
  8. Statistics

The plan

I started with a list:

  1. Make the README more approachable for newcomers
  2. Write a blog postnot a copy of the README
  3. Make a product page – on my website
  4. Make a video – including various output resolutions
  5. Make a GIF – useful where embedding isn’t possible and also allows viewers to see a preview/clickbait
  6. Publish on my Blog, Twitter, Instagram, Dribbble, Vimeo, etc…

The video

The video was kind of obvious, its a visual medium to help understanding, you can expose a lot more functionality with a series of pictures than you ever could with a single screenshot or a limited number of characters.

I decided I wanted something that looked like it was made by Apple. That was obviously a little out of reach 🤪 but that was the goal anyway. So I set out to learn Apple Motion and Final Cut Pro X to edit the video myself. I also purchased an awesome backing track that I felt best fit the design, story, etc…

Finally, I exported a short preview version of the video as an animated GIF since not all sites allow embedding and besides, I wanted viewers to see something that would hopefully entice them immediately.

Making the video - If you’re interested in how I made the video & GIF, I’ll do a follow up post in the future. Let me know in the comments or on Twitter.

The README

Less obvious were the small changes I made, including the tweaks to the README. I carefully ordered the content of that page and also added the animated GIF version of the Video since GitHub doesn’t allow embedding. I also made sure this GIF went at the top, so that mobile clients would also see it immediately.

Previously I had the changelog at the top of the file, which is useful if you’re working on the project or actively monitoring it. In reality however this was a waste of time, so I moved it to the end of the file.

I needed to target newcomers. So I moved the GIF up top and added a new entry that went over the top features and how to get started. I don’t have metrics on this, but I’d be surprised if this hasn’t helped people better understand what Peek is and how easy it is to start benefitting from its use.

The product page

Luckily I use Square Space for my hosting, so making a quick and dirty promo page was quite trivial. The tricky part was deciding what image I wanted to fill the page with, and which screenshot to use as the video placeholder.

In my case, I made the video first, then looked for frames that made sense. However in the end I decided to make a dedicated high-resolution mockup of Peek running on a device.

The blog

Previously when I released my open sourced projects, I’d basically just take a copy of the README and post that on my blog as well. This may seem productive at the time, but I’ve actually found it can be quite detrimental.

The point of the blog post – as well as the dedicated product page – is to drive traffic back to your website. This is super important to build a reputation and awareness of you as a developer, producing quality Open Source Software.

More importantly it will help you build a community as well. Some will contribute back to your projects, others will simply be users.

Social networking

So I finally had all my marketing material, the product page was ready, blog post written – all that was left was to publish everything online for people to see. Plus I had to publish to Cocoapods 😬

Thanks to Twitter’s new 280 character limit, I was able to include all the top features in my Tweet as well. Here’s a snapshot of that first tweet:

Anatomy of the Tweet

I just wanted to pay special attention to this tweet, as I’ve spent a lot of time finessing the structure of my product releases when it comes to Twitter to improve my initial exposure and chance of interaction.

  1. Add a title, nice and short
  2. Make sure to include a link – I found near the top works well
  3. Include a short feature list – or short paragraph if that fits better
  4. Add appropriate hashtags – remember your target audience isn’t always other developers
  5. Most importantly a screenshot or GIF – I can’t stress this one enough!

The release

So everything was ready, how did I manage the release?

I started by uploading the video, this can take time to process and become available so its worth preparing first.

The blog post and product page were already up, just not public yet so I could switch them on at any time.

I also prepare my tweet, instagram post, etc… to keep things consistent but platform specific where appropriate.

Once all the content was prepared, I pushed to Cocoapods and it was released!

Statistics

Its been 5 days since the release and I’m happy to report:

GitHub

After 3 days

  • #1 – Swift projects
  • #4 – Overall
  • #7 – My Profile
  • Over 1700 stars
  • 4 new PRs, 57 Forks

After 5 days

  • #1 – Swift projects
  • #4 – Overall
  • #3 – My Profile
  • Over 2000 stars
  • 11 new PRs, 72 Forks

Website

  • Over 4000 unique visitors on day 1
  • ~400 daily since

Vimeo

After 3 days

  • Over 3000 views so far

After 5 days

  • Over 4000 views so far

Miscellaneous

  • Peek was also featured in iOSDevWeekly for the second time (plus a direct mention on the following Tuesday)
  • Promoted across various other channels and newsletters/lists
  • A few new followers on Twitter and GitHub

Overall I’d say it been a really exciting 5 days. I’m not one of the iOS Elite and I’m not speaking at any events (although I’m interested in doing so). All of that aside, I’ve been able to make a simple tool and get people to notice.

I hope this post gets you a little more excited about marketing your own apps and hopefully gives you some insights into how you can improve awareness of your own projects.

If you’d like to discuss more, ask questions or make suggestions for my next big release, please get in touch or comment below.

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.