Now that Xcode has been installed and the basics of the Swift programming language are covered, it is time to start introducing SwiftUI.
First announced at Apple’s Worldwide Developer Conference in 2019, SwiftUI is an entirely new approach to developing apps for all Apple operating system platforms. The primary goals of SwiftUI are to make app development easier, faster, and less prone to the types of bugs that typically appear when developing software projects. These elements have been combined with SwiftUI-specific additions to Xcode that allow SwiftUI projects to be tested in near real-time using a live app preview during the development process.
Many of the advantages of SwiftUI originate from the fact that it is both declarative and data-driven, topics which will be explained in this chapter.
The discussion in this chapter is intended as a high-level overview of SwiftUI and does not cover the practical aspects of implementation within a project. Implementation and practical examples will be covered in detail in the remainder of the book.
UIKit and Interface Builder
To understand the meaning and advantages of SwiftUI’s declarative syntax, it helps to understand how user interface layouts were designed before the introduction of SwiftUI. Until the introduction of SwiftUI, iOS apps were built entirely using UIKit, together with a collection of associated frameworks that make up the iOS Software Development Kit (SDK).
To aid in the design of the user interface layouts that make up the screens of an app, Xcode includes a tool called Interface Builder. Interface Builder is a powerful tool that allows storyboards to be created that contain the individual scenes that make up an app (with a scene typically representing a single app screen).
The user interface layout of a scene is designed within Interface Builder by dragging components (such as buttons, labels, text fields and sliders) from a library panel to the desired location on the scene canvas. Selecting a component in a scene provides access to a range of inspector panels where the attributes of the components can be changed.
The layout behavior of the scene (in other words, how it reacts to different device screen sizes and changes to device orientation between portrait and landscape) is defined by configuring a range of constraints that dictate how each component is positioned and sized in relation to both the containing window and the other components in the layout.
Finally, any components that need to respond to user events (such as a button tap or slider motion) are connected to methods in the app source code where the event is handled.
At various points during this development process, it is necessary to compile and run the app on a simulator or device to test that everything is working as expected.
SwiftUI Declarative Syntax
SwiftUI introduces a declarative syntax that provides an entirely different way of implementing user interface layouts and behavior from the UIKit and Interface Builder approach. Instead of manually designing the intricate details of the layout and appearance of components that make up a scene, SwiftUI allows the scenes to be described using a simple and intuitive syntax. In other words, SwiftUI allows layouts to be created by declaring how the user interface should appear without worrying about the complexity of how the layout is built.
This essentially involves declaring the components to be included in the layout, stating the kind of layout manager in which they are to be contained (vertical stack, horizontal stack, form, list, etc.), and using modifiers to set attributes such as the text on a button, the foreground color of a label, or the method to be called in the event of a tap gesture. Having made these declarations, all the intricate and complicated details of how to position, constrain, and render the layout are handled automatically by SwiftUI.
SwiftUI declarations are structured hierarchically, making it easy to create complex views by composing small, reusable custom subviews.
While the view layout is being declared and tested, Xcode provides a preview canvas that changes in real-time to reflect the appearance of the layout. Xcode also includes a live preview mode, which allows the app to be launched within the preview canvas and fully tested without the need to build and run on a simulator or device. The SwiftUI declaration syntax’s coverage begins with the chapter Creating Custom Views with SwiftUI.
SwiftUI is Data Driven
When we say that SwiftUI is data-driven, this is not to say that it is no longer necessary to handle user-generated events (in other words, the interaction between the user and the app user interface). It is still necessary, for example, to know when the user taps a button and to react in some app-specific way. Being data-driven relates more to the relationship between the underlying app data and the user interface and logic of the app.
Before the introduction of SwiftUI, an iOS app would contain code responsible for checking the current data values within the app. If data is likely to change over time, code has to be written to ensure that the user interface always reflects the latest state of the data (perhaps by writing code to frequently check for changes to the data or by providing a refresh option for the user to request a data update). Similar problems arise when keeping the user interface state consistent and ensuring issues like toggle button settings are stored appropriately. Requirements such as these can become increasingly complex when multiple areas of an app depend on the same data sources.
SwiftUI addresses this complexity by providing several ways to bind an app’s data model to the user interface components and logic that provide the app functionality.
When implemented, the data model publishes data variables to which other parts of the app can then subscribe. This approach automatically reports changes to the published data to all subscribers. If the binding is made from a user interface component, any data changes will automatically be reflected within the user interface by SwiftUI without the need to write any additional code.
SwiftUI vs. UIKit
With the choice of using UIKit and SwiftUI now available, the obvious question arises as to which is the best option. When making this decision, it is important to understand that SwiftUI and UIKit are not mutually exclusive. In fact, several integration solutions are available (a topic covered starting with the chapter entitled Integrating UIViews with SwiftUI).
SwiftUI provides a faster, more efficient app development environment and makes it easier to make the same app available on multiple Apple platforms (iOS, iPadOS, macOS, watchOS, and tvOS) without making significant code changes.
If you have an existing app developed using UIKit, there is no easy migration path to convert that code to SwiftUI, so it probably makes sense to keep using UIKit for that part of the project. UIKit will continue to be a valuable part of the app development toolset and will be extended, supported and enhanced by Apple for the foreseeable future. When adding new features to an existing project, however, consider doing so using SwiftUI and integrating it into the existing UIKit codebase.
When adopting SwiftUI for new projects, it will probably not be possible to avoid using UIKit entirely. Although SwiftUI comes with a wide array of user interface components, it will still be necessary to use UIKit for certain functionality not yet available in SwiftUI.
In addition, for highly complex user interface layout designs, it may also be necessary to use Interface Builder when layout needs cannot be satisfied using the SwiftUI layout container views.
SwiftUI introduces a different approach to app development than that offered by UIKit and Interface Builder. Rather than directly implementing how a user interface is rendered, SwiftUI allows the user interface to be declared in descriptive terms and then decides the best way to perform the rendering when the app runs.
SwiftUI is also data-driven in that data changes drive the behavior and appearance of the app. This is achieved through a publisher and subscriber model.
This chapter has provided a very high-level view of SwiftUI. The remainder of this book will explore SwiftUI in greater depth.