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
Swift Properties
Use properties for data that is not mutated by the view (a.k.a. data that the view only reads, but not mutates).
@State
Use
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).
@Binding
Use
@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.
ObservableObject
We can think of
ObservableObjectas our interface to the real, UI-independent data/models. It represents SwiftUI’sViews 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.
@Published
Use
@Publishedon the properties of our types conforming to@ObservableObjectwhen we want SwiftUI to be notified of their changes.
When to use what, for ObservableObject
ObservedObject
Use
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.
@StateObject
Similar to
ObservedObject.SwiftUI will instantiate the
@StateObjectassociated value just before running our viewbodyfor the first time.SwiftUI will keep the instance alive for the whole lifecycle of the view.
@EnvironmentObject
Use
@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 theobjectWillChangepublisher of that specificObservableObject.Whenever the
ObservableObjectwill change, all the views subscribed to it will be updated.
Performance Tips
Ensure that our
Views initialization is cheap.Make
bodya pure function, no side effects.Avoid making assumptions on when and how often
bodyis called.
Event Sources
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.
@SceneStorage
Per scene storage
Accessible to
ViewsUsed to restore the scene
It’s basically a
Scene’s version of@State
@AppStorage
Uses UserDefauts behind the scenes
Per app storage
Accessible to
Views andAppUse it to store small sets of data, such as the app settings
