WWDC20: Advancements in SwiftUI

Among numerous advancements in iOS development brought to us in WWDC20 are a number of updates, enhancements, and demonstrations of an overall continued effort to build out the robustness of SwiftUI, furthering its viability as the preferred method of UI development in iOS.
In order to learn as much as possible about these updates to SwiftUI, we built a sample Cities app, with the objectives being to explore the new app lifecycle, new View
types, modifiers, property wrappers, and any other general improvements we found along the way.
The SwiftUI App Lifecycle
Upon creating a new project in Xcode, with the SwiftUIApp
Life Cycle selected, you’ll notice your project is pre-packaged with a new Swift file, named to match your project. This file effectively replaces AppDelegate
and SceneDelegate
, and is all that is needed to startup and run your app. The code will look something like this:
This ContentView
can be any View
type you want your app to begin with. We’re going to create a TabView
to allow our user access to the three different views that comprise our Cities app: CityHomeView
, CityGridView
, and CityListView
.
We are going to modify each tab item using the tabItem()
modifier. In addition to the updates to SwiftUI, WWDC20 brought us some advancements to SF Symbols. SF Symbols 2 offers over 750 new Symbols, multicolor Symbols, localization enhancements, and better optical alignment control with the ability to customize leading and trailing attributes. For each tab item, we’ll provide a SF Symbol Image and associated text.
The new SwiftUI App Lifecycle has dramatically simplified the process of creating and starting up your app, allowing you, the developer, to focus more on the fun stuff, and less on the setup.
Lazy Stacks
SwiftUI in iOS 14 offers new View
types that load lazily. VStack
and HStack
now have lazy counterparts, LazyVStack
and LazyHStack
, to load our content lazily on demand.
When a VStack
or HStack
is created the system also creates all of their subviews. On the other hand, when a LazyVStack
or LazyHStack
is created the system creates each subview only when it is needed to render on screen. These lazy stacks match the performance benefits of UITableView
and UICollectionView
from UIKit.
The benefit of lazy stacks is made apparent through large data sets. In fact, we recommend not using lazy stacks unless you are dealing with a large data set. Let’s walk through some examples.
The third tab in our app, CityListView
shows a long list of city names. A button in the navigation bar toggles between displaying the list using a LazyVStack
and a regular VStack
using a binding called isLazy
. Here’s how it looks:
We started off with a list of approximately 26,500 city names from simplemaps.com. Running on an iPhone 11 Pro the lazy stack loads instantly and is able to immediately scroll smoothly through thousands of names. Unfortunately, scrolling quickly down the list eventually causes the app to run out of memory and crash!
Will VStack
do better? Tapping the toggle button switches to the regular stack and immediately pauses the UI. After a few seconds the app crashes. VStack
attempts to render the view with all 26,500 city names up front and unfortunately it doesn’t succeed.
Whichever way we go it appears that 26,500 names pushes the system too far. After dividing the list of names in half three times down to about 3,300 we are finally able to render the regular VStack
. With about 3,300 names the LazyVStack
is fully capable of loading instantly and scrolling smoothly through the entire list. On the other hand, regular VStack
takes a couple seconds to render the view after tapping the toggle button. Once loaded the VStack
scrolls smoothly through all of the names.
We also tried scrolling through the 26,500 city names using List
which was already available before WWDC20.
Using List
we are able to successfully scroll through all of the names without crashing. However, framerate was noticeably bad. If you need to show an enormous number of rows in a table layout then List
might be preferable to using either a LazyVStack
or VStack
.
Lazy Grids
SwiftUI and iOS 14 also offer us LazyVGrid
and LazyHGrid
for grid layouts. The addition of these views is an exciting enhancement, as they serve as a flexible replacement for UIKit
’s UICollectionView
, a commonly used view type which SwiftUI was previously lacking.
LazyVGrid
and LazyHGrid
are container views that arrange their child views in a grid, growing vertically and horizontally, respectively, and only creating items as needed.
On initialization, you can provide an array of GridItem
's, which essentially describe how the grid should lay out. In our example, we’ll use GridItem(.adaptive(minimum: 180))
, meaning we want our grid to fit as many items as possible in each row, so long as that item has a minimum size of 180 points. We’ll call our array of GridItem
's columns
, since we are going to use a LazyVGrid
.
We could have also used GridItem(.flexible())
if we wanted to specify how many columns to use, or GridItem(.fixed())
to explicitly set the size of the item.
Once we have set our columns, we can create our LazyVGrid
using those columns:
And the result:

What if we wanted a horizontal grid? It’s really quite easy. We just need to set our GridItem
array to account for rows, rather than columns. I could use the same GridItem(.adaptive(minimum: 180))
and ensure we have exactly 180 points for each item, but for variation’s sake, let’s specify that we want exactly 4 rows, with .flexible()
, and give each one a minimum height of 200:

MapKit
SwiftUI in iOS 14 now offers us the ability to easily show and display MapKit views in our SwiftUI views.
We just need a @State
variable to track an MKCoordinateRegion
that will be used for the center of our map.
So, we’ll create a CityDetailView
, showing a map of the provided city, using that city’s coordinates, MapKit, and SwiftUI’s Map
view.
Once we have a City, we can set our @State
variable to track that City’s coordinates in an MKCoordinateRegion
.
And in our view, we can just display that region in a map as such:
Map(coordinateRegion: $region)
The result:

Other New View
Types
Label
Label
is a new UI component to combine an icon with text. The simplest form of a Label
can be created using a title and the name of an image. We’ll do so, using an SF Symbol:
Label("Cities", systemImage: "airplane")
The icon will size accordingly with the font of the text in the label, and will scale for dynamic type. iOS 14 also introduces the ability to change color for SF Symbols, so we can apply view modifiers to this label and consequentially change the color of both the icon and the text.

Label("Cities", systemImage: "airplane")
.font(.title)
.foregroundColor(.blue)
ColorPicker
SwiftUI in iOS 14 also offers a new ColorPicker
. We just need to track a color
property as a @State
variable, and we can set our Label
’s color to match that of the ColorPicker
.

Modal Presentation
SwiftUI’s new fullScreenCover
view modifier allows us to present another view modally, covering as much of the screen as possible. Let’s present a larger version of our image on CityDetailView
when the user taps the image.
We just need to add a @State
variable to track when the modal view has presented, and to add the .fullScreenCover
modifier to our image. Our fullScreenCover
will track the binding to our @State
variable, and we will supply it with View content.
In our newly created CityImageModalView
, we just need an environment property to allow the view to dismiss itself. In the View, we’ll add a Button to dismiss.

Conclusion
SwiftUI continues to develop, expand, and advance its viability as the preferred method of UI development for iOS. The addition of new view types makes it easier to replicate more and more UIKit
views, while its sleekness, flexibility, and intuitiveness, whether it be through the new SwiftUI App Lifecycle or view definition, enhance the simplicity and efficiency of development. Look for SwiftUI to continue to grow in the future, and in the meantime, check out these latest advancements for yourself!