From the this-may-only-be-useful-to-me department, I recently did the stereotypical programmer thing. I procrastinated from doing what I should be doing by instead automating something that bothered me.

One of the many perks of SwiftUI is how easy it is to preview your designs/layouts. In fact, you can even do so across multiple devices:

struct SomeView: View {
    var body: some View {
        Text("Hello, world")
    }
}

struct SomeViewPreviews: PreviewProvider {
    static var previews: some View {
        Group {
            SomeView()
                .previewProvider("iPhone 13 Pro")
            SomeView()
                .previewProvider("iPhone SE (2nd generation)")
        }
    }
}

The above code would present you with two renders of SomeView: one shown on an iPhone 13 Pro, and one on an iPhone SE.

The problem with this, however, is you need to know the exact right incantation of device name in order to please Xcode/SwiftUI. For some devices, like iPhone 13 Pro, that’s pretty straightforward. For others, like iPhone SE (2nd generation), it’s less so.

The good news is, you can get a list of installed simulators on your machine using this command:

xcrun simctl list devices available

It occurred to me, if I can easily query Xcode for the list of installed simulators, surely I can then convert that list into a Swift enum or equivalent that I can use from my code? Hell, I can even auto-generate this enum every time I build, in order to make sure I always have the latest-and-greatest list for my particular machine available.

Enter installed-simulators. It’s a small Swift command-line app that does exactly that. When run, without any parameters, it spits out a file called Simulators.swift. That file looks like this:

import SwiftUI

enum Simulator {
    static let iPhone8 = PreviewDevice(rawValue: "iPhone 8")
    static let iPhone8Plus = PreviewDevice(rawValue: "iPhone 8 Plus")
    /* ...and so on, and so on... */
}

That makes it super easy to test your SwiftUI views by device, without having to worry about the precisely correct name of the device you’re thinking of:

struct SomeViewPreviews: PreviewProvider {
    static var previews: some View {
        Group {
            SomeView()
                .previewProvider(Simulator.iPhone13Pro)
            SomeView()
                .previewProvider(Simulator.iPhoneSE2ndgeneration)
        }
    }
}

Naturally, I prefer this over the alternative.

Since I’m so used to wielding a hammer, I wrote this as a Swift command-line app rather than a Perl script. Sorry, John. Also, I know effectively nothing about releasing apps of any sort for macOS, so goodness knows if this will work on anyone else’s desk but mine.

Nevertheless, I’ve open-sourced it, and you can find it — as well as some more robust instructions — over at Github.