Chapters

Hide chapters

Advanced iOS App Architecture

Third Edition · iOS 13 · Swift 5.2 · Xcode 11

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

Section I

Section 1: 10 chapters
Show chapters Hide chapters

9. Getting Ready for SwiftUI
Written by René Cacheaux

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

More than a framework, SwiftUI is a new paradigm for creating apps in the Apple ecosystem. These are exciting times. We’re in the middle of a journey towards a post Cocoa, Swift-native world. Until now, you didn’t need to diverge from Apple’s Cocoa Objective-C based patterns and Model-View-Controller, MVC, architecture. This was true even if you started to write UIKit apps using Swift. SwiftUI brings a new set of building blocks, paradigms and patterns that are native to Swift. These new tools will help you, and other developers, be drastically more productive. And, more productive developers means better apps for users.

Note: This chapter assumes familiarity with SwiftUI and Combine concepts and terminology. To get hands on practice with SwiftUI and Combine, check out SwiftUI by Tutorials and Combine: Asynchronous Programming with Swift raywenderlich.com books.

This chapter will help you get your app’s architecture ready for SwiftUI. You’ll explore what SwiftUI means for app architecture and how SwiftUI is different than UIKit. You’ll also get some advice for practicing, preparing and planning SwiftUI integration. You’ll walk through things you can change in your codebase today, even if you don’t plan on integrating SwiftUI for a while. After reading this chapter, you’ll be able to decide how and when you should start incorporating SwiftUI into your existing iOS apps.

What SwiftUI means for app architecture

Architecting features with SwiftUI is new, fun and exciting. SwiftUI brings new powerful patterns and tools for you to use when architecting the Swift code behind your app’s UI. You end up writing less architectural boilerplate and more domain specific logic. And, you get a lot of behaviors, such as Publisher subscription, for free. SwiftUI enables you to break down your UI into small and reusable pieces that are much lighter than UIViewController. You can decompose large portions of UI code into small encapsulated components without paying a performance penalty. All to say, SwiftUI helps you build well architected UI systems.

Note: SwiftUI is quite new, so establishing architecture best practices will take some time. The content in this edition is based on initial explorations with SwiftUI. Advice and best practices will evolve over time. I recommend keeping an eye on SwiftUI content written by developers that have had a chance to ship production apps using SwiftUI.

The architectural patterns that SwiftUI enables are based on some of the industry’s latest best practices and paradigms. This is great news, especially if you’ve already invested time in learning any of these paradigms such as functional reactive programming. You can now use these paradigms without fighting the UI framework. If you’ve ever tried applying non-Apple paradigms to UIKit based iOS apps, you know how difficult it is to program against the framework. With SwiftUI, you won’t be fighting the UI framework when applying the latest thinking in UI architecture.

SwiftUI goes even further than the industry’s latest approaches. SwiftUI was clearly designed with UI architecture in mind. For example, view dependencies in SwiftUI are explicit. This makes architecting for SwiftUI incredibly satisfying because you can easily see all of a view’s dependencies when opening a SwiftUI file.

Today, SwiftUI is not a complete application framework. Currently, SwiftUI does not have application level APIs. Because of this, even when using SwiftUI, you’re still architecting within the context of UIKit. You still use a UIApplicationDelegate and you still need to give your root UIWindow a root UIViewController. This means if you want to use SwiftUI, you’ll be building mixed UIKit and SwiftUI apps for the foreseeable future. Fortunately, incorporating SwiftUI into a UIKit architecture is incredibly easy. This is awesome because you’ll be able to gradually adopt SwiftUI over time.

Because most developers who are interested in using SwiftUI will be working from an existing UIKit iOS app, this chapter focuses on how to get an existing app’s architecture ready for SwiftUI.

Architecting with SwiftUI versus UIKit

SwiftUI expects and enables a different kind of architecture than UIKit. UIKit favors an Objective-C object-oriented imperative MVC approach where every type is a reference and every view is mutable. This is different from SwiftUI’s reactive functional approach where immutable value types are the norm. Architecting features using SwiftUI might feel strange at first. Don’t let this discourage you! Once you get the hang of it, architecting with SwiftUI is delightful. You’ll be able to build features much faster using SwiftUI compared to UIKit.

When to start building with SwiftUI

SwiftUI is available on iOS 13 and above. Therefore, in order to use SwiftUI you’ll need to require your users to upgrade to iOS 13. Or, you’ll need to build the same features in both UIKit and SwiftUI so that you can ship your app to pre-iOS 13 devices. You can use #available and @available to fork control flow depending on SwiftUI’s availability. Because SwiftUI requires iOS 13, most teams won’t adopt SwiftUI extensively until the majority of their user base has upgraded to iOS 13.

Practicing

Because architecting with SwiftUI is so different than architecting with UIKit, it’s worth experimenting and practicing with SwiftUI in order to become familiar with SwiftUI’s mechanics. This section covers some of the architecture skills you can practice to gain that familiarity.

Decomposing views

First, practice breaking down large SwiftUI views into smaller reusable views. Take an existing screen in one of your apps and build the UI using SwiftUI. Build the screen in one SwiftUI View. Don’t worry about hooking your practice SwiftUI view into networking and persistence subsystems. Use @State for any mutable UI state. And, for your first practice views, avoid @ObservedObject and @EnvironmentObject because they add unnecessary complexity that isn’t critical to learning the architectural foundations of SwiftUI.

Understanding the view lifecycle

Once you’re comfortable breaking views down, you can get familiar with the View lifecycle, i.e. when View struct values are created, destroyed and recreated. A great way to do this is to place log statements in View initializers and in var body computed property closures. Do this at all levels of the view hierarchy and notice what views get re-created in response to state changes. This will help you understand which views are best suited for holding onto references to longer lived objects such as dependency containers.

Connecting UIKit to SwiftUI

It’s also worth exploring how to bridge between UIKit and SwiftUI. You can practice incorporating SwiftUI views through UIViewController presentation APIs and through UIViewController containment APIs. Try creating and providing an @ObservableObject to a UIHostingController’s SwiftUI View. You can also practice injecting @Environment values and @EnvironmentObjects by calling modifiers on a UIHostingController’s SwiftUI View. This will help you build intuition for how to provide values and objects from UIKit into SwiftUI.

Preparing

Even if you’re not ready to ship features built with SwiftUI, there are changes you can make today to your existing codebase to prepare for SwiftUI. Here are some ideas.

Migrating to value types

Take a look at your app’s data model types. SwiftUI works best when data models are designed as value types. As a matter of fact, @State can only store values. If your data models are designed as reference types, consider refactoring them into struct or enum types.

Moving state to state containers

While data model types themselves should be value types, you’ll most likely need a state container to hold values. State containers are just objects with value type properties. In UIKit, you can use a UIViewController, a view model or a Redux store as a state container. Once you’re ready to start building features with SwiftUI, you’ll need to decide whether you want to store your data model values in a @State container or in an @ObservableObject container. Refactoring your data model types to value types will help you easily use your existing data model within SwiftUI.

Planning

You’ll most likely be gradually adopting SwiftUI into your current codebase. You might not have enough time to ease SwiftUI integration by making broad sweeping changes across your entire codebase. In addition, SwiftUI does not provide all the functionality available in UIKit. So it’s a good idea to plan your codebase’s SwiftUI adoption ahead of time.

Starting with new screens

When looking for things to build using SwiftUI, consider building new screens or components. You can incorporate SwiftUI components into existing view controllers via UIViewController containment APIs and you can incorporate SwiftUI screens via UIViewController presentation APIs. It’s a good idea to start here because building a single screen or component limits the amount of concepts you’ll need to be familiar with to build a well architected SwiftUI feature. You won’t have to design for things like navigation and dependency scopes. The lifetime of a screen or component is relatively easy to manage compared to a SwiftUI View that can present and dismiss many screens.

Selecting a state management strategy

Once you know what to build with SwiftUI, you can start thinking about state management. If your SwiftUI screen or component is immutable and does not need to observe changes in state, you don’t need to worry about state management. You can simply use properties on the root View and subviews to hold onto data model values. Or, if the data is global, you can extend EnvironmentValues and provide the values as @Environment values. Make sure to only do this for truly global values because any SwiftUI View will be able to request any custom values added to EnvironmentValues. If you do need to manage mutable state, you can use @State, @ObservedObject and @EnvironmentObject.

Migrating existing screens

If you’re done shipping new screens or if you don’t have anything new to build, you can start planning how to migrate existing screens from UIKit to SwiftUI. But first, you might be wondering whether you should re-write existing UIKit code rather than plugging your existing UIViewControllers and UIViews into SwiftUI via UIViewRepresentable. This depends on your migration strategy. You could either take a bottom up approach or a top down approach.

Key points

  • SwiftUI is available starting on iOS 13 and it requires a deployment target of iOS 13 or above.
  • Even when using SwiftUI, you’re still architecting within the context of UIKit.
  • Because architecting with SwiftUI is so different than architecting with UIKit, it’s worth experimenting and practicing with SwiftUI in order to become familiar with its mechanics.
  • Even if you’re not ready to ship features built with SwiftUI, there are changes you can make today to your existing codebase to prepare for the future, such as migrating to value types and moving state to state containers.
  • You’ll most likely be gradually adopting SwiftUI into your current codebase.
  • When looking for things to build using SwiftUI, consider building new screens or components.
  • You can take a bottom up or top down approach to migrating an app from UIKit to SwiftUI.
  • If you can’t wait and would like to see some SwiftUI architecture code you can check out the source on Github at https://github.com/raywenderlich/swiftui-example-app-koober.

Where to go from here?

That wraps up getting started with SwiftUI architecture. But, there’s one more thing… We are in the process of rebuilding this book’s example app, Koober, entirely in SwiftUI. If you can’t wait and would like to see some SwiftUI architecture code you can check out the source on Github at https://github.com/raywenderlich/swiftui-example-app-koober. The example is not finished at the time of writing. However, you can follow along as we work towards completing the examples.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now