Data Essentials in SwiftUI
Description: Data is a complex part of any app, but SwiftUI makes it easy to ensure a smooth, data-driven experience from prototyping to production. Discover @State and @Binding, two powerful tools that can preserve and seamlessly update your Source of Truth. We'll also show you how ObservableObject lets you connect your views to your data model. Learn about some tricky challenges and cool new ways to solve them — directly from the experts! To get the most out of this session, you should be familiar with SwiftUI. Watch “App essentials in SwiftUI” and "Introduction to SwiftUI"
Questions to ask when creating a new View
- What data does this view need?
- How will the view manipulate that data? Is it read only?
- Where will the data come from? (To determine the source of truth)
- Who owns the data? (where the source of truth should come from)
Why do we need to use property wrappers to store our data?
Our views only exist temporarily: after SwiftUI completes their rendering, the structs instances go away. When we add a property wrapper such as
@State to our
View, SwiftUI takes over its managent, making sure it's there even when our
Views are re-instantiated over and over.
When to use what, for view-only sources of truth
- Use properties for data that is not mutated by the view (a.k.a. data that the view only reads, but not mutates).
Statefor transient data owned by the view.
- By using
@State, we're saying that the source of truth belongs to this View (a.k.a. it's local to this view).
@Bindingfor reading and mutating data owned by an ancestor.
@Bindingcreates a data dependency between our view and the ancestor owning that source of truth.
- It's ok to build a new binding from an existing binding.
- We can think of
ObservableObjectas our interface to the real, UI-independent data/models. It represents SwiftUI's
Views data depenency.
ObservableObjectrepresents the part of our model/data that exposes data to our view, but it is not necessarily the whole data/model.
- Classes conforming to
ObservableObjectautomatically gain a publisher, however we can write our own, for example we can use a publisher for a timer, or use a KVO publisher to observe an existing model.
- When our type conforms to
ObservableObject, we're creating a new Source of Truth and teaching SwiftUI how to react to its changes.
@Publishedon the properties of our types conforming to
@ObservableObjectwhen we want SwiftUI to be notified of their changes.
When to use what, for
ObservedObjectwhen the source of truth is separate from its UI.
- SwiftUI does not get ownership of the
ObservedObjectinstance we're providing, it's our responsibility to manage its lifecycle.
- Similar to
- SwiftUI will instantiate the
@StateObjectassociated value just before running our view
bodyfor the first time.
- SwiftUI will keep the instance alive for the whole lifecycle of the view.
@EnvironmentObjectwhen we need to pass data between views that have other views in-between that don't need that data.
Behind the scenes of SwiftUI Property Wrappers
- Whenever we use
@ObserveObjectin our views, SwiftUI will subscribe to the
objectWillChangepublisher of that specific
- Whenever the
ObservableObjectwill change, all the views subscribed to it will be updated.
- Ensure that our
Views initialization is cheap.
bodya pure function, no side effects.
- Avoid making assumptions on when and how often
The closure associtate with these events is launched in the main thread, dispatch to less priority queues to avoid slow updates
Source of Truth Lifetime Extended Lifetime
In iOS 14 SwiftUI can automatically manage restoring the state of our app even after our process has been killed. this it done via two new property wrappers:
Both are lightweight stores that we use in conjunction with our model.
- Per scene storage
- Accessible to
- Used to restore the scene
- It's basically a
Scene's version of
- Uses UserDefauts behind the scenes
- Per app storage
- Accessible to
- Use it to store small sets of data, such as the app settings