Data in SwiftUI, Part 2: Views as a function of data

Part 2 in a series on understanding data in SwiftUI. We will talk about the key that makes principles in part 1 possible in SwiftUI. And how this resulting in a reduction of the complexity of UI development.

We know from part 1 that data is the main focus for SwiftUI, but without cooperation from a view and framework, it might not be a pleasant experience implementing it.

Views as a function of state #

Even though you set the data right, you have a single source of truth, and you set dependency correctly. Doing this in UIKit might still result in a big chunk of code. That's because, by nature, UIKit is an event-driven user interface; it needs someone to coordinate all of these events and glue them together. That is why we need UIViewController in UIKit.

Here is an example from WWDC 2019 session . It is a music player app with a PlayerView as a parent view, which contains PlayerButton showing play/pause image based on isPlaying state.

A music player app - Pausing

A music player app - Playing

An overview diagram of interactions between each view in UIKit

The above diagram should familiar to you, PlayerViewController holds a reference of PlayerView and PlayButton . It keeps a single source of truth ( isPlaying ) in sync between PlayerView and PlayButton . PlayButton holds a reference of isPlaying , change the image (play/pause) based on this state and fire an action when got tapped. PlayerViewController listens to button action and changes the state accordingly. Once playing state change, it changes the color of the song title in PlayView .





var isPlaying : Bool = false {

didSet {



}

}



func viewDidLoad ( ) {

configureView ( )

loadData ( )

}



private func configureView ( ) {





}



@objc func playButtonDidTap ( sender : Any ) {





}

As you can see, the fact that UIKit communicates using events makes it difficult to know what the resulting view would be at a given time. And there are so many places that can go wrong.

Views are a function of state, not of a sequence of events.

– WWDC 2019, session 226

If UIKit said to be an event-driven user interface, SwiftUI would be data-driven. The above quote from WWDC 2019 session sums the situation of UIKit and SwiftUI nicely.

View in UIKIt usually a result of sequences of events, whether target-action, delegate, or notification. View in SwiftUI, on the other hand, designed to depend solely on data.

Let see some example.

struct PlayerView : View {

let episode : Episode

@ State private var isPlaying : Bool = false



var body : some View {

VStack {

Text ( episode . title ) . foregroundColor ( isPlaying ? . white : . gray )

Text ( episode . showTitle ) . font ( . caption ) . foregroundColor ( . gray )

PlayButton ( isPlaying : $isPlaying )

}

}

}

struct PlayButton : View {

@ Binding var isPlaying : Bool



var body : some View {

Button ( action : {

self . isPlaying . toggle ( )

} ) {

Image ( systemName : isPlaying ? "pause.circle" : "play.circle" )

}

}

}

You might not understand some of the syntaxes, but we can all agree that a SwiftUI view is quite easy to understand. We can declare views in the form of function that takes data as an arugment. PlayerView 's episode title color change according to isPlaying . PlayButton image showing play/pause based on isPlaying . We know exactly how it looks based on a given data, isPlaying .

Following is the same view interaction diagram, but this time for SwiftUI.

An overview diagram of interactions between each view in SwiftUI

Declarative UI #

SwiftUI said to be declarative UI. It has a way to declare all principles we learn in this declarative world. We can declare data as a source of truth or dependency, and view as a function of those data. SwiftUI will do take care of the rest for us.

The declarative UI make SwiftUI shine, the framework handle everything that we have to do it manually in UIKit. It makes the concept of view controller not relevant anymore in SwiftUI.

The purpose of the view controller is to manage views and their interaction. Most of the codes in view controller are for responding to user interaction from its views. Setting up target-action to a button, listen for a delegate. Observe to model change and response to that by reload your table view or change some labels. You have to do all of this manually, which is error-prone, and the complexity grows as your app grows.

SwiftUI does all the heavy lifting, which allows us to focus on things that matter, manage the data of your app by defining the right source of truth and its dependency.

The whole purpose of view controller is to keep your data in sync with your view

The fact that we don't have to manage data ourselves makes the complexity in UI development significantly reduce.

In the following article, we will go through all the tools available, including the one shown in the example @State and @Binding .

Related Resources #

Data flow in SwiftUI, Part 1: Data

Data flow in SwiftUI, Part 3: Tools

Data Flow Through SwiftUI

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron

Tweet

Share

← Home