Exploring SwiftUI with Recipes

Apple recently released SwiftUI, which is a new declarative system for building user interfaces across Apple platforms. When Mac OS X came out, Apple introduced Objective-C and Project Builder including the NeXT-inspired Interface Builder tools (since integrated in XCode). Interface Builder was, at the time, quite an enchanting and powerful experience letting you build and wire up a UI in a WYSIWYG editor while maintaining the ability to integrate custom components. To me, this felt like a big step forward back then, combining the developer productivity I’d experienced with Borland Delphi and the power and performance I’d been used to building Windows apps in Visual C++.

Of course, Objective-C development become mainstream with the release of the iPhone, but I was using it before it was cool. Here’s a screenshot of an app I built back in 2004 to automatically pull photos off my phone over Bluetooth and present them in a seekable timeline UI (before I cut image assets for buttons, later screenshots lost to the mists of time).

iLifeBlog circa 2004

Interface Builder often felt close to best in class, but always had its limits - every complex iOS project I’ve worked on has ended up eventually implementing UI in code and mostly giving up on what is now called Storyboard. The UI-in-imperative-code experience makes iteration cycles longer, is pretty fiddly and the code ends up being super verbose. By contrast, I’ve often found the more declarative Android XML layout system quite a productive experience and over the last few years have built web projects in React. React combines a mostly declarative syntax and reactive re-rendering when state changes, producing to a whole new level of frontend developer experience.

I was super excited, therefore, to hear about SwiftUI and over the holiday I found some time to take it for a spin. My go-to project when exploring a new UI toolkit or platform is to port / implement a recipes app - it’s a simple enough project to complete quickly but complicated enough - involving list and detail views, search, arbitrary data fetching from a server etc that rough edges in the environment usually show up. SwiftUI-recipes is the result of my holiday fun - you’ll find all the code for this demo in that github repo, I hope it’s useful if you choose to build something in SwiftUI yourself.

UI

Thoughts on SwiftUI

Tutorials

The online Apple Swift UI tutorials are really, really good. This is a wonderfully executed learning experience. The tutorials are nicely paced - they ramp gradually but get relatively deep into the details. The tour de force here is a beautifully designed series of transitions between the steps you follow as you compose the tutorial project in SwiftUI.

Here’s a quick video to give you a sense:

The next step to be followed is clearly highlighted on the left. A center pane shows the current code you have in the file in question, with changes from this step neatly highlighted. A preview of how this changes the UI is shown on the right. Everything is rendered very dynamically, with beautiful motion effects, to show just what you need at the given moment - the preview animates in and out of view, hiding itself when the step requires focus on code and appearing again when there is something interesting to look at. The designers have also mixed in useful little explainer sections with prose and diagrams to explain the bigger picture.

I expect this experience for teaching APIs will be emulated widely (indeed, the Android Jetpack Compose tutorials take a similar shape, but are not as beautifully executed 1 ), it’s great. Bravo to the team who worked on this, I can only imagine how much effort went into sweating these details.

If I had one complaint about the SwiftUI tutorials it would be that the example code they build on includes some neat supporting classes (e.g. the code for loading JSON) which is never explained as being developer-provided rather than part of the framework. It took me a while when constructing my own app from scratch to understand why that neat thing that looked like part of the framework was mysteriously unavailable.

Declarative syntax

SwiftUI’s declarative syntax is very concise and expressive. I mentioned above that Android layout XML felt pretty good when I started using it in 2007, but today the XML boilerplate feels ugly and clunky (Android does have Jetpack Compose now which is a kotlin based equivalent of SwiftUI, I haven’t had a chance to try it yet, I intend to!).

SwiftUI has a nice fluent style. It feels intuitive. I like it. The code to produce this row layout looks as follows: recipe row

struct RecipeRow: View {
...    
    var body: some View {
        HStack {
            LoadableImageView(with: recipe.img, placeholder: "🍽")
                .scaledToFit()
                .frame(width:80, height:80)
                .cornerRadius(8.0)
                .padding(8.0)

            VStack(alignment: .leading) {
                Spacer()
                
                Text(recipe.title)
                  .font(.headline)
                  .fontWeight(.semibold)
                  .lineLimit(1)
                
                Text(recipe.summary.trimmingCharacters(in: .whitespacesAndNewlines))
                  .font(.caption)
                  .fontWeight(.light)
                  .lineLimit(1)
                  .padding(.top, 3.0)

                Spacer()
            }.padding(8.0)

            Spacer()

        }
    }
}

Design tools

A major innovation, is how tightly integrated the XCode tools are with the code itself. The IDE does an almost flawless job of figuring out which UI component the code around the cursor applies to and provides a UI based inspector view where modifiers and properties can be set if you don’t want to write code. You can also add autogenerated code snippets for UI elements chosen from a GUI and it works! I probably shouldn’t have been so surprised that it works, but I haven’t seen an experience like this be so robust before.

Alongside the code editor and inspector, XCode can show a live preview of the UI you are generating, and how it renders across multiple form factors in its “Canvas” view. It’s a little weird. You configure what devices to render and what data to pass in code but then have to decide whether you want to see a “Live Preview” or “static mode”. Live Preview seems to run something like a full simulator in the background and can render UIView subclasses. In static mode only SwiftUI views are fully rendered. I mostly just kept this in live preview mode which loaded and refreshed quickly. From time to time (e.g. when you clean the build, but also if you make a non-trivial change), the preview just stops working and you have to manually click “Resume” to get it going again. Even the docs seem not to understand exactly when or why this will happen: “You might need to click the Try Again or Resume button above your preview.”. This weirdness aside, the Canvas view was super useful and I barely had to launch the full Simulator at all while building this little app as I could test everything more or less instantly in the Canvas view.

struct RecipeList_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone SE", "iPhone 11 Pro Max"], id: \.self) { deviceName in
            RecipeList()
                .previewDevice(PreviewDevice(rawValue: deviceName))
                .previewDisplayName(deviceName)
        }
    }
}

Rough edges

Overall, the experience was good and I would definitely use SwiftUI for my next iOS project. There are some weird rough edges though.

  • As mature as XCode is, its automatic code formatting still sucks. I frequently found myself fighting the auto indentation and there is no “just fix the formatting in this file please” menu option or key combo that works. I think ^-L (“Editor -> Structure -> Re-indent”) is supposed to do this but it simply doesn’t. In 2020, code formatting should be taken care of by the IDE.
  • Runtime errors crash the Canvas renderer but produce extremely unhelpful error messages and debugging what’s actually gone wrong either requires launching the simulator or trial and error.

Recipes App

The source code of the app is available on github SwiftUI-recipes. If you’d like to get a sense for how a (tiny) completed project in SwiftUI looks please take a look. In here you’ll find:

  • recipe data models
  • fetching of lists and detailed objects from a JSON API
  • parsing of JSON into model objects
  • async image fetching from the network
  • funky emoji placeholders for images not loaded yet
  • detail UI generated dynamically based on the content for a given recipe (e.g. optional tab view tabs elided if detail not present in response)
  • search box wired up to the list view data source in a reactive way (which was remarkable easy to code)
  • some yummy recipes

UI

Enjoy!


  1. I don’t actually know which came first, but I assume it was the SwiftUI one. ↩︎

Contents