Skip to content

The iPod touch Is My Favourite Device for iOS Development


It's important to test across various screen sizes, which the iOS simulator is good for, but it's also important to test on real devices where possible. I currently have an iPhone 11 Pro, an iPhone 6, and 2 iPod touches. Out of all these I find the iPod touch to be the best device for a lot of iOS development.

Keep Reading →

Four Squares version 2.1


Release Notes

Four Squares 2.1 adds support for manually uploading completed games to iCloud, including games completed in Four Squares 1.0. Games completed in Four Squares 1.0 can also now be deleted.

Four Squares version 2.0


Release Notes

Four Squares 2.0 is a huge update bringing new modes, customisations, features, and an overhauled UI.

New Modes

In Time Attack mode you start with only 30 seconds on the clock. Every pattern you get right will add 3 more seconds to the clock. How long can keep going?

Speedrun mode gives you 3 lives to try and reach of sequence of 10 in the fastest time.

New Customisations

Old and new themes are available, along with brand new sound packs.

Existing themes have been updated to better support both light and dark mode.

Brand New UI

The UI has been reworked to make customisation easier and support more platforms. Look out for a macOS app in the near future!

Completed Games

Each game you play is now saved and can be viewed in the app.

You can even choose to play the same sequence to keep working on your high score!

App Clip

Four Squares now includes an App Clip, so you can share a completed game with a friend and they can try to beat your score without having to install the app.

My WWDC 2021 Wishlist


With WWDC 2021 just around the corner I've been thinking about what I'd like to see there.

A lot of the popular discourse around this time of year is focussed on features of the operating systems but I want to look at what I'd like to see as a developer for Apple platforms.

I love to develop for Apple platforms but it can often be a painful process. May is like a christmas for Apple developers.

Keep Reading →

Mapping Optional Binding to Bool


When displaying an alert in SwiftUI, if the value used to calculate whether the alert is presented is both Optional and does not conform to Identifiable1 it is often recommended to use a separate flag, similar to:

struct ContentView: View {
    @State private var alertText: String?
    @State private var isPresentingAlert = false

    var body: some View {
        Button("Show Alert") {
            self.alertText = "Alert Text"
            self.isPresentingAlert = true
        }
        .alert(isPresented: $isPresentingAlert) {
            Alert(title: Text(alertText!))
        }
    }
}

There are 2 main downsides to this:

  1. alertText is not set back to nil, which may cause bugs and will increase memory usage (even if only a little in this case)
  2. The isPresentingAlert flag needs to be managed

To work around these issues I create a small extension to Binding the allows this same code to be updated to:

struct ContentView: View {
    @State private var alertText: String?

    var body: some View {
        Button("Show Alert") {
            self.alertText = "Alert Text"
        }
        .alert(isPresented: $alertText.mappedToBool()) {
            Alert(title: Text(alertText!))
        }
    }
}

The extension is fairly small and simple:

import os.log
import SwiftUI

extension Binding where Value == Bool {
    /// Creates a binding by mapping an optional value to a `Bool` that is
    /// `true` when the value is non-`nil` and `false` when the value is `nil`.
    ///
    /// When the value of the produced binding is set to `false` the value
    /// of `bindingToOptional`'s `wrappedValue` is set to `nil`.
    ///
    /// Setting the value of the produce binding to `true` does nothing and
    /// will log an error.
    ///
    /// - parameter bindingToOptional: A `Binding` to an optional value, used to calculate the `wrappedValue`.
    public init<Wrapped>(mappedTo bindingToOptional: Binding<Wrapped?>) {
        self.init(
            get: { bindingToOptional.wrappedValue != nil },
            set: { newValue in
                if !newValue {
                    bindingToOptional.wrappedValue = nil
                } else {
                    os_log(
                        .error,
                        "Optional binding mapped to optional has been set to `true`, which will have no effect. Current value: %@",
                        String(describing: bindingToOptional.wrappedValue)
                    )
                }
            }
        )
    }
}

extension Binding {
    /// Returns a binding by mapping this binding's value to a `Bool` that is
    /// `true` when the value is non-`nil` and `false` when the value is `nil`.
    ///
    /// When the value of the produced binding is set to `false` this binding's value
    /// is set to `nil`.
    public func mappedToBool<Wrapped>() -> Binding<Bool> where Value == Wrapped? {
        return Binding<Bool>(mappedTo: self)
    }
}

The extension isn't tied directly to showing an alert or a sheet and can be used in any context, but this is one of the better examples of its usage.

This extension is available on GitHub under the MIT license.

1 If it does conform to Identifiable use alert(item:content:)

Nevis version 1.1.0


Release Notes

  • Add support for opening PKGs, including PKGs inside ZIPs and DMGs
  • Improve detection of downloaded files
  • Ensure app is brought forward when opening from status bar icon
  • Fix handling of DMGs if Nevis is force quit and reopened

Nevis version 1.0.1


Release Notes

  • Improve handling of watch folder
  • Improve notification text when an error occurs

Supporting Multiple Swift Package Versions Without Breaking Compatibility


The Xcode 12 beta includes Swift 5.3 but drops support for iOS 8.x. This means that Swift packages that support iOS 8 will cause a warning:

The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.

It's not possible to remove this warning within a project that depends on a Swift package with a deployment target of iOS 8, but it is possible to fix this in the dependency without removing support for iOS 8 for older versions of Swift. There are multiple way this can be accomplished.

Keep Reading →

Running UI Tests on Mac Catalyst


While working on the 2.0 update for Gathered I have been trying to develop the app multiple platforms simultaneously. SwiftUI will solve this problem in the future, but I wish to support some OS versions that SwiftUI does not support.

As part of this I have been creating UI tests to test performance, but ran in to an issue when running the UI tests on macOS using Mac Catalyst:

Running tests...
The bundle “PerformanceXCTests” couldn’t be loaded because it is damaged or missing necessary resources. Try reinstalling the bundle.
(dlopen_preflight(...): no suitable image found.  Did find:
	...: code signature in (...) not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?))
Keep Reading →