Working with IndexPaths

IndexPath’s provide an abstraction over the indexing of our structured data. They are used by common controllers and views, such as UICollectionView, UITableView and NSFetchedResultsController.

IndexPath is basically just an array of integers that defines a ‘path’ that can be used to represent your data. Lets take a look at a simple, but common example.

I’m going to start off my showing simple examples so if you want to jump straight into the more interesting stuff, scroll past the next section 🙂

Quick Example

Just to ensure we’re all on the same page, lets look at an example where we have a contacts application, with each contact grouped by their company name.

Apple:
  - Steve Jobs
  - Alan Kay
  - Andy Hertzfeld
Microsoft:
  - Bill Gates
  - Paul Allen
Google:
  - Larry Page
  - Sergey Brin

If I wanted to reference Paul Allen I could create an IndexPath as such:

IndexPath(item: 1, section: 1) // Paul Allen

So as we can see defining IndexPath’s is actually quiet simple. What about using an IndexPath to find Alan Key?

dataSource
    .companies[indexPath.section]
    .employees[indexPath.item]

Easy peasy!

Adavanced Indexing

So as we’ve seen, using a single IndexPath in isolation is really simple. What if I wanted to use my current IndexPath to find the employee in a list, before the this one?

Well, on its own we can’t really do that because IndexPath‘s don’t have a reference to other IndexPath‘s. Which makes sense because they can be used in any contexts.

More importantly the fact that our grouping is 1 level deep and specific to the company name, is specific to the implementation in a specific part of an application.

So when would we ever want to do this in the first place?

Introducing UICollectionViewLayout

Have you ever implemented a UICollectionViewLayout (or FlowLayout) and realised how complicated it becomes to keep track of all of your IndexPath‘s? It gets even more complicated when you have to deal with headers, footers and perhaps even more supplementary and decoration views.

Recently I began implementing a custom layout for the 5th or 6th time and decided I really wanted to make dealing with IndexPath‘s a lot simpler than it had been in the past. Specifically I wanted the following features:

  1. To be able to iterate over all of my dataSource’s IndexPath‘s
  2. To be able to query my dataSource for specific indexPaths
  3. To be able to easily differentiate the various kinds of IndexPath‘s I use (i.e. headers, footers and items)

Table Layout

For simplicity lets think about how we would build a simple layout that looks like a UITableView, with section headers and footers as well as the items for each section.

So we discussed above how IndexPath‘s don’t know about other IndexPath‘s so how do we plan on solving that? Well luckily enough our DataSource does know about all of our IndexPath‘s, so we can easily write an extension on Set to fetch all of our IndexPath‘s for us.

Easy peasy!

Adavanced Indexing

So as we’ve seen, using a single IndexPath in isolation is really simple. What if I wanted to use my current IndexPath to find the employee in a list, before the this one?

Well, on its own we can’t really do that because IndexPath‘s don’t have a reference to other IndexPath‘s. Which makes sense because they can be used in any contexts.

More importantly the fact that our grouping is 1 level deep and specific to the company name, is specific to the implementation in a specific part of an application.

So when would we ever want to do this in the first place?

Introducing UICollectionViewLayout

Have you ever implemented a UICollectionViewLayout (or FlowLayout) and realised how complicated it becomes to keep track of all of your IndexPath‘s? It gets even more complicated when you have to deal with headers, footers and perhaps even more supplementary and decoration views.

Recently I began implementing a custom layout for the 5th or 6th time and decided I really wanted to make dealing with IndexPath‘s a lot simpler than it had been in the past. Specifically I wanted the following features:

  1. To be able to iterate over all of my dataSource’s IndexPath‘s
  2. To be able to query my dataSource for specific indexPaths
  3. To be able to easily differentiate the various kinds of IndexPath‘s I use (i.e. headers, footers and items)

Table Layout

For simplicity lets think about how we would build a simple layout that looks like a UITableView, with section headers and footers as well as the items for each section.

So we discussed above how IndexPath‘s don’t know about other IndexPath‘s so how do we plan on solving that? Well luckily enough our DataSource does know about all of our IndexPath‘s, so we can easily write an extension on Set to fetch all of our IndexPath‘s for us.

Before we do that lets also add an extension to IndexPath to support a property called kind which will allow us to determine whether we’re dealing with a header, footer or item.

internal extension IndexPath {

    enum Kind: Int {
        case header
        case footer
        case item
    }

    init(kind: Kind, item: Int, section: Int) {
        switch kind {
        case .header:
            self = [section, -1, 0]
        case .footer:
            self = [section, item, 1]
        case .item:
            self = IndexPath(item: item, section: section)
        }
    }
}

You may notice we’re specifying 3 index values for our custom IndexPath‘s. The first index represents the section, the second represents our item and the last value represents whether this is a header or a footer.

For all other IndexPath‘s we use the standard convenience method.

Data Source

Now we have a better way to represent our IndexPath‘s, we can add an extension to Set that will collect all of the IndexPath‘s from our DataSource, in this case our UICollectionView.

public extension Set where Element == IndexPath {

    init(from view: UICollectionView) {
        var indexPaths: Set<IndexPath> = []
        let sectionCount = view.dataSource?.numberOfSections?(in: view) ?? 0

        for section in 0..<sectionCount {
            let headerIndexPath = IndexPath(
                kind: .header,
                item: -1,
                section: section
            )
            indexPaths.insert(headerIndexPath)

            let itemCount = view.dataSource?
                .collectionView(view, numberOfItemsInSection: section) ?? 0

            for item in 0..<itemCount {
                let itemIndexPath = IndexPath(
                    item: item,
                    section: section
                )
                indexPaths.insert(itemIndexPath)
            }

            let footerIndexPath = IndexPath(
                kind: .footer,
                item: itemCount, 
                section: section
            )
            indexPaths.insert(footerIndexPath)
        }

        self.init(indexPaths)
    }
}

If we were to manually configure our IndexPath‘s we would end up with something like this.

// Apple
IndexPath(kind: .header, item: -1, section: 0),
IndexPath(item: 0, section: 0),
IndexPath(item: 1, section: 0),
IndexPath(item: 2, section: 0),
IndexPath(kind: .footer, item: 3, section: 0),
// Microsoft
IndexPath(kind: .header, item: -1, section: 1),
IndexPath(item: 0, section: 1),
IndexPath(item: 1, section: 1),
IndexPath(kind: .footer, item: 2, section: 1),
// Google
IndexPath(kind: .header, item: -1, section: 2),
IndexPath(item: 0, section: 2),
IndexPath(item: 1, section: 2),
IndexPath(kind: .footer, item: 2, section: 1),

Querying

So now we have an array of IndexPath things get a lot simple. First of all, we can easily sort our array and because our custom IndexPath initializer ensures all paths will order correctly.

Secondly we can easily query our array for the IndexPath‘s we care about now. So lets take a look at an extension that will allow us to query our IndexPath‘s.

func filter(include kinds: IndexPath.KindMask, inSections sections: [Int]) 
    -> [SubSequence.Element] {
        return filter { sections.contains($0.section) && kinds.contains($0.kind) }
}

With this one simple function, we can query as such:

// fetch all IndexPath's for headers and items only 
// in the first 2 sections

indexPaths
    .sorted()
    .filter(include: [.header, .item], inSections: [0, 1])

Now that we have a simple flat array of IndexPath‘s we can also easily iterate over it invarious ways:

// Use an iterator
var iterator = indexPaths.makeIterator()
iterator.next()

Since we’re dealing with a simple array now, we can even index into the array to get the next/previous IndexPath without having to consider what section we’re in and whether or not we’re the first/last item in that section, etc…

Summary

IndexPath‘s are a great way to represent your data but can sometimes become unwieldly as your structures get more complex.

Hopefully this has given you some interesting ideas to help simplify your approaches and implementations as well.

You can download the playground to give it a try, or you can checkout the GIST here.

Type-Safe UserDefaults API

As the Swift APIs have evolved, Apple has also been improving their own frameworks to make them easier to work with in Swift. Two API improvements I’ve personally appreciated are how we work with NSAttributedString keys, and Notification names.

Deriving inspiration from those additions, I thought UserDefaults could probably benefit from a similar approach.

Keys

Lets start by defining a UserDefaults.Key type similar to NSAttributedString.Key.

extension UserDefaults {

    public struct Key: Hashable, RawRepresentable, ExpressibleByStringLiteral {
        public var rawValue: String

        public init(rawValue: String) {
            self.rawValue = rawValue
        }

        public init(stringLiteral value: String) {
            self.rawValue = value
        }
    }

}

Notice we’re adding ExpressibleByStringLiteral support to allow us to simplify key definitions.

let foo: UserDefaults.Key = "foo"

Type-Safety

Now lets add API that allows us to use our new Key type instead of raw strings. While we’re at it lets also add type-safety to allow us to infer function calls.

Note: This is a lighweight approach that doesn’t provide key-to-value type-safety. You will still need to know the expected type that’s returned for a given key.

func set<T>(_ value: T?, forKey key: Key) {
    set(value, forKey: key.rawValue)
}

func value<T>(forKey key: Key) -> T? {
    return value(forKey: key.rawValue) as? T
}

While we’re at it, let’s add a subscript too.

subscript<T>(key: Key) -> T? {
    get { return value(forKey: key) }
    set { set(newValue, forKey: key.rawValue) }
}

Finally we need to an API we can use when registering our initial values.

func register(defaults: [Key: Any]) {
    let mapped = Dictionary(uniqueKeysWithValues: defaults.map { (key, value) -&gt; (String, Any) in
        return (key.rawValue, value)
    })

    register(defaults: mapped)
}

API Usage

Now we have a clean API let define some keys:

public extension UserDefaults.Key {
    static let showLineNumbers: UserDefaults.Key = "ShowLineNumbers"
    static let fontFamily: UserDefaults.Key = "SourceFontFamily"
    static let fontSize: UserDefaults.Key = "SourceFontSize"
    static let defaultFontSize: UserDefaults.Key = "DefaultSourceFontSize"
}

Now we can make use of these keys and define some initial values:

let defaults = UserDefaults.standard

defaults.register(defaults: [
    .showLineNumbers: false,
    .fontFamily: defaultFont.familyName!,
    .fontSize: defaultSize,
    .defaultFontSize: defaultSize
])

showNumbers = defaults[.showLineNumbers]
defaults[.showLineNumbers] = false

Conclusion

I think this is a clean solution that feels familiar to other iOS framework APIs and is simple enough to start adding to an existing project immediately with no overhead.

There are other approaches to this problem, but I found this to be a lightweight solution that adds value from the outset, without incurring additional complexity in your code.

Checkout the link to get the full source, including more overrides and conveniences for dealing with various types.

Clean dynamic font API in Swift

There are generally a couple of ways to get custom fonts loaded into your apps.

  1. Include them in your bundle and load them at launch time via info.plist
  2. Dynamically load fonts after launch, even from a remote url

Loading many fonts via your info.plist is generally impractical as it has a detrimental effect on your apps launch time. However it removes the need for any code to load the fonts into memory and guarantees they exist well before you need to access them. As an added bonus, fonts loaded this way can be defined in XIB’s and Storyboard’s.

Dynamically loading fonts has the advantage of being able to load the fonts on-demand and you can even download them from a remote url. This approach also doesn’t require you to touch your info.plist.

I recently worked on an app that contained around 15-20 fonts, most of which were not required during the early stages of the apps lifecycle. So I opted for dynamically loading the fonts on-demand.

For the purposes of this article, I’d like to focus on a clean API pattern that I’ve used across various apps.

API Implementation

When dynamically loading fonts, we generally need 3 pieces of information. The font’s name, filename and extension.

public protocol FontCacheDescriptor: Codable {
    var fontName: String { get }
    var fileName: String { get }
    var fileExtension: String { get }
}

Now we have a type that describes our custom font. In most cases on iOS, we deal with TrueType fonts, so let’s define a default implementation for that.

public extension FontCacheDescriptor {
    public var fileExtension: String {
        return "ttf"
    }
}

The approach I’m going to suggest makes use of enum types. With that knowledge in hand, lets add a another extension to make use of the rawValue when our enum is RawRepresentable.

public extension FontCacheDescriptor 
   where Self: RawRepresentable, Self.RawValue == String {
      public var fontName: String {
          return rawValue
      }

      public var fileName: String {
          return rawValue
      }
}

Here’s comes the meat of this API. In order to load our custom font we need to perform the following tasks.

  1. Register the font with the system and load it into memory (only if its not already cached)
  2. If we’re targeting iOS 11+, scale the font’s size based on the current UIContentSizeCategoy
  3. Make a descriptor for the font

So lets add a convenience initializer to UIFont.

extension UIFont {

    public convenience init(descriptor: FontCacheDescriptor, size: CGFloat) {
        FontCache.cacheIfNeeded(named: descriptor.fileName, fileExtension: descriptor.fileExtension)
        let size = UIFontMetrics.default.scaledValue(for: size)
        let descriptor = UIFontDescriptor(name: descriptor.fontName, size: size)
        self.init(descriptor: descriptor, size: 0)
    }

}

API Usage

With all the code in place, we can now easily create clean APIs around our custom fonts for use in our UI code.

Lets say we have a font called Graphik and it has 4 variants.

extension UIFont {
    
    // The `rawValue` MUST match the filename (without extension)
    public enum Graphik: String, FontCacheDescriptor {
        case regular = "GraphikAltWeb-Regular"
        case medium = "GraphikAltWeb-Medium"
        case regularItalic = "GraphikAltWeb-RegularItalic"
        case mediumItalic = "GraphikAltWeb-MediumItalic"
    }
    
    /// Makes a new font with the specified variant, size
    public convenience init(graphik: Graphik, size: CGFloat) {
        self.init(descriptor: graphik, size: size)
    }
    
}

Now our UI code can simply create an instance of this font.

let font = UIFont(graphik: .regular, size: 16)

Conclusion

This API provides a clean and simple approach that provides various benefits:

  1. Typed font names
  2. Dynamic type support
  3. Dynamic font loading
  4. Font caching

Pie Progress View (iOS and macOS)

Following on from my previous post about cross platform development, I wanted to showcase a simple view/layer implementation I recently built for an app I’m working on.

The design requires a pie chart to represent progress. I initially built it using CAShapeLayer however this quickly proved to be the wrong approach since the shape layer would attempt to ‘morph’ between values, rather than simply adjust the chart.

At this point I decided to move to a more custom approach. I also knew this would lend itself nicely to cross platform development, since layer’s are generally identical across both iOS and macOS.

I plan on doing some more in-depth posts that go into the deeper details of making a cross-platform application, but for the purposes of this post I’ll keep things short.

Cross Platform

I generally write the code for one platform first, one file at a time. Then assess the requirements to work out any extensions, typealias‘s, etc.. I may need.

On iOS its relatively simple to get a cgPath from a UIBezierPath however on macOS, we need to do this ourselves. So I wrote an equivalent extension.

#if os(OSX)
import AppKit

public extension NSBezierPath {
    var cgPath: CGPath { /* implementation */ }
}
#endif

Next up, I needed some typealias‘s to make it easier to use a single call throughout my code.

#if os(OSX)
    import AppKit
    public typealias Color = NSColor
    public typealias View = NSView

    private func scale() -> CGFloat {
        return NSScreen.main?.backingScaleFactor ?? 1
    }

    extension NSView {
        internal var nonOptionalLayer: CALayer {
            return layer!
        }
    }
#else
    import UIKit
    public typealias Color = UIColor
    public typealias View = UIView

    internal func scale() -> CGFloat {
        return UIScreen.main.scale
    }

    extension UIView {
        internal var nonOptionalLayer: CALayer {
            return layer
        }
    }
#endif

Coordinate System

One of the most interesting differences between iOS and macOS development, is that the y-coordinates are inverted. Where iOS expects the origin to be top-left, macOS expects the origin to be bottom-left.

To normalise the origin for both platforms, NSView provides a simple isFlipped property. Returning true for this property, moves the origin to the top-left, matching what we’d expect on iOS.

public override var isFlipped: Bool {
    return true
}

Progress View

The code itself is extremely simple. We simply subclass CALayer to provide our own drawing for each frame. This allows us to animate the progress when its value changes. We even get all the benefits of implicit animation, etc…

I then wrapped the layer with a custom (UI/NS)View, added some IBDesignable support and some configurable properties to make it easier to work with.

Lastly I added a setProgress(progress:animated:) function which was as simple as disabling the implicit animation when animated == false.

public func setProgress(_ progress: CGFloat, animated: Bool) {
    guard animated else {
        CATransaction.setDisableActions(true)
        self.progress = progress
        CATransaction.setDisableActions(false)
        return
    }

    self.progress = progress
}

Summary

Building a cross platform component isn’t too difficult. Focusing on UI components at this level, allows the greatest amount of reuse as well. Adding storyboard/XIB support also aides the user of the component.

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.

Code Review with Git Worktree

I’ve been using a little known feature for some time now and thought it might be worthy of a post for those (like myself) who prefer the Console world of GIT.

Scenario

Para-phrasing from the Git Documentation:

You are in the middle of a refactoring session, unable to commit and you need to checkout another branch to code review, reference or something else. You might typically use git-stash to store your changes away temporarily, however, your working tree is in such a state of disarray that you don’t want to risk disturbing any of it. Use a Git Worktree.

I think we can all agree that this is an all too common scenerio?

Worktree’s are also extremely useful during Code Review. You don’t want to commit your changes, but need to checkout someone elses branch to ensure the work they’ve done actually works. Or perhaps you need to checkout the code to better understand how it works.

Worktree’s

In simple terms, a worktree represents a linked clone of your master worktree. This means its extremely fast to work with and because its generally transient/temporary, you can simply delete it once you’re done.

Workflow

So lets take a look at a typical workflow.

# git worktree add $PATH $BRANCH
# Adds a new worktree at 'path' and performs a checkout of 'branch'
# path:   prs/5.2.0
# branch: release/5.2.0

git worktree add prs/5.2.0 release/5.2.0

Hack away

Simply `cd` into the directory and hack away. The sub-folder is a complete checkout of the branch you specified and has its own `.git` folder. So any changes you make here are affected only on that branch – leaving your original branch untouched.

cd prs/5.2.0``open .

Push and Prune

If you made changes to your worktree, simply push those changes back up to your origin as usual. Then you can remove the sub-folder and prune your worktree from Git.

git push # optional
cd ../..
rm -rf prs # you can remove just the 5.2.0 folder if you have multiple worktree's
git worktree prune

List

Its important to remove your Worktree when done, because Git only allows 1 worktree per branch. If you need to remember where you created your Worktree, you can list them using:

git worktree list

Conclusion

Worktree’s are a great tool to have in your bag. Using this approach I found I’m more likely to checkout someone’s branch during Code Review to ensure it works.

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.

Peek: All new design

Today I’m excited to announce Peek 5.0 with an all new design and some pretty exciting features. Start inspecting your iOS applications now!

All new features

Here’s the top 7 new features in Peek 5.0

Unified Inspectors

All inspectors and attributes have now been unified into a single window, making inspection simpler and faster than ever before.

Collapse/Expand Headers

Feeling overwhelmed with all the information Peek has to offer? Simply tap the header to expand/collapse any section. Peek will even remember your choice across launches!

Nested Inspectors

Peek now supports nested Inspectors. This powerful feature allows Peek to surface even more detail about your application. In fact Peek 5.0 more than doubles the number of attributes it can inspect.

Previews

Views, images, colours and more can now provide snapshot previews to help you better identify what you’re inspecting.

Reporting

An all new reporting system allows you to report issues, including screenshots and metadata using the native iOS share sheet.

Accessibility

Peek itself is now more accessible with Dynamic Type, but Peek can also surface accessibility details from your application.

You can now search within Peek, making it easier than ever to inspect your apps.

Once setup, it’s as easy as pressing one of the volume keys on your device!

What is Peek?

Peek is an open source framework that provides runtime inspection of your application while its running on your device (or Simulator).

  • Developers can use Peek to inspect their user interfaces at runtime.
  • Designers can verify that the applications meets their design specifications.
  • Testers and QA can check accessibility identifiers, validate behaviour and report issues.

Peek is a tool to aide you at all stages of your development process.

How does Peek work?

Peek scans your entire user interface on the screen then provides overlays with layout information and attribute inspectors.

Peek includes an intelligent filtering system to best determine which views you care about while ignoring those 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.

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.

Most importantly Peek doesn’t interfere with your applications logic or user interface in anyway. It provides read-only inspection to guarantee you’re seeing live-values only!

Less Code

Thanks to an all new architecture Peek is also now smaller. Providing more features with much less code, leaving a very small footprint on your application.

Where can I get it?

Peek is open source and can be downloaded directly from GitHub. So start inspecting your apps now!

Update

If you’re interested in learning more about Peek and how you can market your own Open Source Software, checkout my follow up post: Peek… behind the curtains

Protocols & Mutability in Swift

Protocol Oriented Programming (POP) has become synonymous with the Swift programming language. Its an inherently better fit for Composition and generally leads to better architecture and code reuse. However its often difficult to deal with Mutability. 

Objective-C

In the Objective-C world, common practice (perhaps learned from Apple’s SDK) was to create a Mutable subclass that provided read/write properties. This was extremely cumbersome and required a lot of maintenance. I think in Swift we can do better.

Example Problem

Lets say want a type to represent a control in our UI. This type should be immutable and has a single property defining its current state.

public protocol Control { 
    var state: State { get }
}

public final class Button: Control {
    public let state: State
}

Now lets define some API that will return an instance of our Control.

public func button(from json: JSONDictionary) -> Button {
    var control: Control = makeControl(from json: JSONDictionary)
    control.state = .default
    return control
}

The code above will throw an error at compile time, because state is read-only. Now we could obviously make it { get set } but that would allow our API consumers to modify the variable too.

Solution

Instead we can introduce a Mutable variant of our protocol. 

public protocol Control { 
    var state: State { get }
}

internal protocol MutableControl: Control {
    var state: State { get set }
}

public final class Button: MutableControl {
    public internal(set) var state: State
}

Notice that our Mutable variant is marked as Internal. This is the secret ingredient to making this work.

Now we can simply update our API to return our MutableControl without needing to expose internal features.

public func button(from json: JSONDictionary) -> Button {
    var control: MutableControl = makeControl(from json: JSONDictionary)
    control.state = .default
    return control
}

Summary

This is really nice feature and approach to solve immutability when using Swift Protocols. If you liked this post or want to get in touch, I’d love to hear from you.