SwiftUI and the Evolution of Apple UI Layouts

 

Rob Busack

Rob Busack is a mobile developer with a deep passion for iOS and climbing mountains.

Updated Sep 9, 2020

Now that SwiftUI has been publicly available for a year how does it stack up? Watch our talk by Rob Busack for code samples comparing it to each of the previous Apple UI layout paradigms, and a dive into SwiftUI.

 

Apple announced SwiftUI just over a year ago, at WWDC 2019.  In my opinion, this is the fourth major paradigm option for defining user interfaces for iOS & Mac OS, and hopefully the best yet.

Options for defining User Interfaces on iOS:

  1. WYSIWYG Storyboards (or NIB files, or XIB files)
  2. Setting UIView.frame manually, doing all the rectangle math yourself
  3. UI Constraints
  4. Swift UI

Why Now?

Apps built with Swift UI only work on phones running iOS 13, which became widely available in September of 2019. I waited a year to dig into Swift UI, for two reasons:  

  1. Any new technology is likely to have some rough edges and undergo a lot of refinement and change between the proverbial version 1.0 and version 1.1. I prefer to skip the early-adopter stress and wait until things are a little more stable before I try to work with them.  
  2. I’m interested in building practical production-ready apps, and that means choosing a deployment target (the minimum iOS version that a user must be running in order to install your app) that works for most people out there.  

My rule of thumb is that your app’s deployment target should always be an iOS version that’s at least a year old. Now that we’re here in summer 2020, the majority of iOS users out there are running iOS 13 and could install an app that includes Swift UI, and the quality of 3rd party Swift UI tutorials out there is outstanding; making it the perfect time to seriously dig into Swift UI as an option for production apps.

Some History

First, a trip down memory lane into ancient computing history: the late 1990’s. Computing was about desktops, Apple’s main product line was the Macintosh, Internet access was likely a 56k modem temporarily dialing in over a land-line and cell phones were their most basic — if you had one at all it’s most advanced feature might have been T9 texting via its number pad. Steve Jobs was estranged from the Apple Computer Inc. and was busy co-founding NeXT Computer Inc. NeXT had built some obscure but forward-thinking software and tools, including the Objective-C-based NeXTSTEP operating system, and its developer tools known as Project Builder and Interface Builder.

Smash cut to 1997 when the ailing Apple Computer purchased NeXT, bringing Steve Jobs back to Apple, and rolling the legacy of NeXTSTEP, Objective-C and Interface Builder into Apple developers’ futures for decades to come. Interface Builder was slick: a WYSIWYG  (What You See Is What You Get) user interface editor, where a developer could build a user interface by dragging components around in a NIB file. NIB stands for “NeXT Interface Builder.” When we got the very first version of Mac OS X from Apple, released in 2001, those developer tools were present: Project Builder for writing Objective-C and Interface Builder for drag-and-drop building of user interfaces. NIB files later got renamed to XIB files when they got an XML format: modern Storyboards are still essentially the same concept.

Storyboards

Storyboard, NIBs, or XIBs are all conceptually similar; they are WYSIWYG user interface definition files. They have pros and cons. You can go from a blank new project to a functioning user interface just by dragging and dropping components. It makes for impressive WWDC demos. My summation is: easy things are especially easy, and hard things are especially hard. If you want to build a dynamic interface where UI components do any amount of complex resizing or moving around, it is challenging with the WYSIWYG editor’s semi-static picture of your UI.

An even bigger negative impact is that the file format for Storyboard/NIB/XIB files is not human-readable to most developers. Sure, it’s XML, but I’ve never heard of anyone hand-editing this file, which is very common for other file types in a project. This leads to other problems: those files don’t work well with version control, and it’s hard to see what changed by looking at the diff in a commit. Worse, merge conflicts are often irreconcilable, forcing you to revert to some past version of the file and have each developer re-make their changes more carefully.

Once upon a time, it even meant that part of your app’s behavior wouldn’t show up in a text search. You could have a variable being written to (IBOutlet) or a function being called (IBAction) that a text-search of your project wouldn’t reveal, which has caused me a great deal of pain in the past. (Fortunately, it appears the text search thing has been fixed in the latest version of Xcode if you are still using Storyboards.) Overall, for me, this meant that Storyboards were not the way to go when building a production app with any sort of lifetime.

UIView.frame and manual rectangle math

So if not WYSIWYG UI definition, what’s the alternative? I prefer having a user interface entirely represented in code, so it is developer-readable, searchable, debuggable, customizable, and works with version control.

From the first release of Mac OS X in 2001, that could be done by writing code that manually sets the ‘frame’ on a UIView object, defining the precise rectangle on the screen which that view should occupy. This was conceptually simple since ‘frame’ is a CGRect, which was simply a struct with four floats:  x, y, width, height. You could precisely control the positioning and behavior of any view in your UI. The flip side of that is that almost nothing is done for you in terms of updating UI layouts. For visual precision, this often meant writing a lot of code. That included both code that initially set up your UI, and code to handle resizing in your UI, forcing you to put UI-defining code in at least two places. This was the only available alternative to the WYSIWYG woes until 2012, which saw the release of iOS 6 introducing UI Constraints as an option. For history’s completeness, the original iPhone was first released in 2007, and the concept of Apple’s App Store for 3rd party apps was first released in 2008, marking the beginning of when you could write your own apps for the iPhone. So those first ~5 years of writing iOS apps, manually setting UIView.frame was the way to go. While it was extra work, it paid off in terms of representing complex interfaces, especially ones that move or resize. In the early years of iPhone development, it was made easier by the fixed screen resolutions, without a departure from the original 320x480 screen until the iPad debuted in 2010.

UI Constraints

Apple introduced its concept of constraints in iOS 6 in 2012, which they refined significantly until iOS 9 in 2015, which included the added concept of anchors. A constraint (specifically, an instance of NSLayoutConstraint) was an object that represented the relative sizing/positioning of one view to another. For example, you could constrain a UIButton to be in the bottom right corner by creating a constraint that the button’s right edge would be 10 pixels less than its superview’s right edge, and it’s bottom edge would be 10 pixels less than its superview’s bottom edge. While that was very similar to the layout-thinking developers had to do with manually setting the UIView.frame rectangle of the button, the difference is that if you used Apple’s UI Constraints, then updates to maintain that button’s relative position when the superview’s size changed would be done automatically for you according to those constraints; whereas if you had set the frame manually, you’d have to set it manually every time the superview’s size might have changed. (“Automatically” is still a little bit of a double-edged sword: it’s great when it works right, but it can be a bit extra head-scratchy to debug when some view size or position isn’t behaving exactly as you intended.) In addition to the programmatic constraints API, Apple also offered ways to define the same type of constraint objects through the Storyboard WYSIWYG editor, and through a curious ASCII syntax that Apple called the Visual Format Language, which was an interesting idea, but weird and limited.

Swift UI

In 2019 with iOS 13, Apple introduced Swift UI, which is a major new paradigm here. It shows a lot of potential for being the best option for defining iOS and macOS user interface layouts yet. It has the advantage that everything is in code. Amazingly, the amount of code necessary to define a user-layout appears to be greatly reduced compared to the programmatic options that came before. Furthermore, it’s elegantly declarative and makes a reactive-programming paradigm natural. It represents a departure from the MVC (Model View Controller) architecture we’ve followed for decades, and a move towards and MVVM (Model-View-ViewModel) architecture, which does a better job of keeping as much logic out of your view’s definition code as possible. And on top of it all, there’s a live preview that’s visible within Xcode, so that you can see the results of the UI definition code you’re editing in real-time, faster than re-compiling & re-running the app in the simulator.

Although I am still early in my exploration of SwiftUI, I’m very optimistic about SwiftUI as the future of defining iOS and macOS interfaces with Swift UI!