Daily coverage of Apple’s WWDC 2019 conference, by John Sundell.

A Swift by Sundell spin-off.

A first look at SwiftUI: Apple’s declarative new UI framework

Declarative UI programming patterns have become incredibly popular over the last few years. On the web with frameworks like React and Vue.js, in cross-platform development environments like React Native and Flutter, and through native tools like RxSwift and RxCocoa — declarative UIs and the reactive principles behind them have truly taken many development communities by storm.

It’s therefore especially exciting to see Apple step into this scene, with their own, completely native declarative UI framework — called SwiftUI. While there’s a ton of functionality to be discovered and experimented with in this new UI framework for all of Apple’s platforms — let’s start by taking a first look at some of the fundamentals of SwiftUI, and how it lets us drastically reduce the amount of code needed to produce common forms of UIs and interactions.

It all starts with a view

One key aspect of most declarative UI frameworks is that they aim to boil any kind of UI down into a series of components — which can then be combined and composed in order to form different sets of views, animations, and interactions.

In SwiftUI, a component is simply called a view, and is defined through the View protocol — which only has a single property requirement, a body — which interestingly is also, in turn, a View. That’s really important in terms of the API’s design, since it makes the whole system completely recursive — as views can easily be embedded inside of other views.

In their own code samples, Apple makes heavy use of several new Swift 5.1 features, for example the new “DSL-like” syntax — which allows return statements to be omitted — and the new some keyword, which enables a protocol with associated types to be used as a return type. While I’ll cover all of those new features in great detail in upcoming articles on Swift by Sundell — let’s take a look at how they let us express View implementations in a very nice and concise way:


struct WelcomeView: View {
    var body: some View {
        Text("Welcome to my fantastic app!")
    }
}
                    

Without any syntactic sugar, the above is basically equivalent to this:


struct WelcomeView: View {
    var body: Text {
        return Text("Welcome to my fantastic app!")
    }
}
                    

Regardless of which syntax we’ll end up using, what we’ve done above is to define a new view (which importantly is not a UIView or an NSView, but a new kind of SwiftUI view) — that in turn displays a text when rendered. To display our view inside of an app, we can use the new UIHostingController view controller type to embed it into any standard UIKit app:


let vc = UIHostingController(rootView: WelcomeView())
                    

The beauty of that design, is that it enables us to quite easily plug code written using SwiftUI into an app written with good old fashioned UIKit (never thought I’d call UIKit “old fashioned”, but here we are), since a UIHostingController instance acts just like any other view controller — it can be pushed onto a navigation controller, presented modally, and so on.

Rendering a list of items

Now let’s take a look at how we can use SwiftUI to perform a really common task when building apps for any Apple platform — rendering a list of content. Let’s say we wanted to render a list of articles, and enable the user to tap one article in that list to go to some sort of detail view.

We’ll start by making our Article model conform to the Identifiable protocol — which is not a requirement, but enables SwiftUI to uniquely identify each model instance without any additional code on our part. The Identifiable protocol only requires our model to have some form of Hashable identifier, such as a UUID:


struct Article: Identifiable {
    let id: UUID
    let title: String
    let preview: String
}
                    

Next, let’s create our actual list view, which will again be a type conforming to the View protocol — this time returning a List as part of its body implementation, which will take each element within our list view’s array of articles, and convert it into a Text based on that article’s title — like this:


struct ArticleListView: View {
    let articles: [Article]

    var body: some View {
        List(articles) { article in
            Text(article.title)
        }
    }
}
                    

The above code is all we need in order to render a UITableView-like interface where each row displays the title of an article — pretty impressive!

One really nice aspect of Swift UI’s API is that it’s very much designed to be scalable in terms of how much we’d like to customize any given aspect of the resulting UI. So while our first, simple implementation already gives us a fully functioning list — with a few small steps we can start tweaking it into something that looks much nicer.

For example, in order to also display each article’s preview text below its title, we can create another Text view, and put both of those texts into a VStack that’ll align them vertically in a stack-like fashion. We’ll set our VStack to align all of its members according to its leading edge, and we’ll also customize the fonts used to render each text as well:


List(articles) { article in
    VStack(alignment: .leading) {
        Text(article.title).font(.headline)
        Text(article.preview).font(.subheadline)
    }
}
                    

With our row rendering code complete — let’s now implement navigation. To do that, we’ll start by wrapping our List view in a NavigationView (which is the SwiftUI equivalent of a UINavigationController), and we’ll also give our list a navigation bar title — which will automatically be displayed in our UI’s navigation bar when the list is the currently active view:


NavigationView {
    List(articles) { article in
        VStack(alignment: .leading) {
            Text(article.title).font(.headline)
            Text(article.preview).font(.subheadline)
        }
    }.navigationBarTitle(Text("Articles"))
}
                    

And just like that, we’ve enabled our UI to be navigated. Now all that remains is to actually perform some form of navigation when a row is tapped — which we’ll do by wrapping each row’s VStack in a NavigationButton that has an ArticleDetailView as its destination view.

Here’s what our complete implementation of ArticleListView will now look like:


struct ArticleListView: View {
    let articles: [Article]

    var body: some View {
        NavigationView {
            List(articles) { article in
                NavigationButton(
                    destination: ArticleDetailView(article: article),
                    label: {
                        VStack(alignment: .leading) {
                            Text(article.title).font(.headline)
                            Text(article.preview).font(.subheadline)
                        }
                    }
                )
            }.navigationBarTitle(Text("Articles"))
        }
    }
}
                    

With the above in place, we can now move on to implementing ArticleDetailView and the other top-level components that our app needs — each completely self-contained and isolated, and each automatically reusable in many different kinds of situations.

Conclusion

I don’t think it’s hyperbolic to describe SwiftUI as a game changer for anyone building apps on Apple’s platforms. While we’ll dive a lot deeper into SwiftUI and all of its features in future articles — I hope that this first look as given you a glimpse of what kind of programming model that this new framework is using, and how it’ll most likely require all Swift developers to start rethinking how we build and compose our UIs.

Thanks for reading! 🚀