SwiftUI @
State & Data Flow.
@dana.allwhite
Contents.
🔎 Basic Concepts - Source of Truth, Property Wrapper
🔎 Internal - @State, @Binding
🔎 External - ObservableObject, EnvironmentObject
(Single) Source of Truth
# source of truth - wikipedia
Single source of truth (SSOT) is the practice of structuring information models and associated data schema such that every
data element is mastered (or edited) in only one place. Any possible linkages to this data element (possibly in other areas of the
relational schema or even in distant federated databases) are by reference only. Because all other locations of the data just refer
back to the primary "source of truth" location, updates to the data element in the primary location propagate to the entire system
without the possibility of a duplicate value somewhere being forgotten.
Property Wrapper
To wrap a property with some additional behavior when it’s written and read.
# property wrapper - Swift Language Guide
@State - Source of Truth of View
struct PlayerView : View {
let episode: Episode
var isPlaying: Bool
var body: some View {
VStack {
Text(episode.title)
Text(episode.showTitle).font(.caption).foregroundColor(.gray)
Button(action: {
self.isPlaying.toggle()
}) {
Image(systemName: isPlaying ? "pause.circle" : "play.circle")
}
}
}
}
@State - Source of Truth of View
struct PlayerView : View {
let episode: Episode
@State private var isPlaying: Bool
var body: some View {
VStack {
Text(episode.title)
Text(episode.showTitle).font(.caption).foregroundColor(.gray)
Button(action: {
self.isPlaying.toggle()
}) {
Image(systemName: isPlaying ? "pause.circle" : "play.circle")
}
}
}
}
View Update
View Update
View Update
View Update
@Binding - Reference to Source of Truth
struct PlayerView : View {
let episode: Episode
@State private var isPlaying: Bool
var body: some View {
VStack {
Text(episode.title)
Text(episode.showTitle).font(.caption).foregroundColor(.gray)
// Button(action: {
// self.isPlaying.toggle()
// }) {
// Image(systemName: isPlaying ? "pause.circle" : "play.circle")
// }
PlayButton()
}
}
}
@Binding - Reference to Source of Truth
struct PlayButton: View {
@State var isPlaying: Bool = false
var body: some View {
Button(action: {
self.isPlaying.toggle()
}) {
Image(systemName: isPlaying ? "pause.circle" : "play.circle")
}
}
}
isPlaying
PlayerView
isPlaying
PlayButton
@Binding - Reference to Source of Truth
struct PlayButton: View {
@Binding var isPlaying: Bool = false
var body: some View {
Button(action: {
self.isPlaying.toggle()
}) {
Image(systemName: isPlaying ? "pause.circle" : "play.circle")
}
}
}
A property wrapper type that can read and write a value owned by a source of truth.
@Binding - Reference to Source of Truth
struct PlayerView : View {
let episode: Episode
@State private var isPlaying: Bool
var body: some View {
VStack {
Text(episode.title)
Text(episode.showTitle).font(.caption).foregroundColor(.gray)
PlayButton(isPlaying: $isPlaying)
}
}
}
State Management
State Management - SwiftUI
SwiftUI Components using @Binding
Data from External Source
Property Wrapper Creating Dependency
ObservableObject @ObservedObject Direct
EnvironmentObject @EnviromnetObject Indirect
ObservableObject protocol
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var landmarks = landmarkData
}
objectWillChange
ObservableObject - @ObservedObject
struct LandmarkList: View {
@ObservedObject var userData: UserData
var body: some View {
NavigationView {
List {
Toggle(isOn: $userData.showFavoritesOnly) {
Text("Show Favorites Only")
}
ForEach(userData.landmarks) { landmark in
if !self.userData.showFavoritesOnly || landmark.isFavorite {
// ~~~~
}
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
LandmarkList(userData: UserData())
EnvironmentObject - .environmentObject(_)
// SceneDelegate
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView:
LandmarkList()
.environmentObject(UserData()))
self.window = window
window.makeKeyAndVisible()
EnvironmentObject - @EnvironmentObject
struct LandmarkList: View {
@EnvironmentObject private var userData: UserData
var body: some View {
NavigationView {
List {
Toggle(isOn: $userData.showFavoritesOnly) {
Text("Show Favorites Only”)
}
ForEach(userData.landmarks) { landmark in
if !self.userData.showFavoritesOnly || landmark.isFavorite {
// ~~~
}
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
When to Use?
@EnvironmentObject
@ObservableObject
EnvironmentObject - @Environment
.
1. . - single source of truth
2. State source of truth , view function of state .
3. @State framework view change ,
@Binding souce of truth reference
4. @ObservedObject dependency ,
@EnvironmentObject view dependency
Reference.
- SwiftUI by Tutorials (Raywenderlich)
- Data Flow Through SwiftUI (WWDC 2019)
- SwiftUI Essential : Handling User Input
- Data in SwiftUI, Part 1: Data
- Single Source of Truth - Wikipedia

SwiftUI - State & Data Flow

  • 1.
    SwiftUI @ State &Data Flow. @dana.allwhite
  • 2.
    Contents. 🔎 Basic Concepts- Source of Truth, Property Wrapper 🔎 Internal - @State, @Binding 🔎 External - ObservableObject, EnvironmentObject
  • 3.
    (Single) Source ofTruth # source of truth - wikipedia Single source of truth (SSOT) is the practice of structuring information models and associated data schema such that every data element is mastered (or edited) in only one place. Any possible linkages to this data element (possibly in other areas of the relational schema or even in distant federated databases) are by reference only. Because all other locations of the data just refer back to the primary "source of truth" location, updates to the data element in the primary location propagate to the entire system without the possibility of a duplicate value somewhere being forgotten.
  • 4.
    Property Wrapper To wrapa property with some additional behavior when it’s written and read. # property wrapper - Swift Language Guide
  • 5.
    @State - Sourceof Truth of View struct PlayerView : View { let episode: Episode var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }
  • 6.
    @State - Sourceof Truth of View struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } }
  • 7.
  • 8.
  • 9.
  • 10.
  • 12.
    @Binding - Referenceto Source of Truth struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) // Button(action: { // self.isPlaying.toggle() // }) { // Image(systemName: isPlaying ? "pause.circle" : "play.circle") // } PlayButton() } } }
  • 13.
    @Binding - Referenceto Source of Truth struct PlayButton: View { @State var isPlaying: Bool = false var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } isPlaying PlayerView isPlaying PlayButton
  • 14.
    @Binding - Referenceto Source of Truth struct PlayButton: View { @Binding var isPlaying: Bool = false var body: some View { Button(action: { self.isPlaying.toggle() }) { Image(systemName: isPlaying ? "pause.circle" : "play.circle") } } } A property wrapper type that can read and write a value owned by a source of truth.
  • 15.
    @Binding - Referenceto Source of Truth struct PlayerView : View { let episode: Episode @State private var isPlaying: Bool var body: some View { VStack { Text(episode.title) Text(episode.showTitle).font(.caption).foregroundColor(.gray) PlayButton(isPlaying: $isPlaying) } } }
  • 16.
  • 17.
  • 18.
  • 19.
    Data from ExternalSource Property Wrapper Creating Dependency ObservableObject @ObservedObject Direct EnvironmentObject @EnviromnetObject Indirect
  • 20.
    ObservableObject protocol final classUserData: ObservableObject { @Published var showFavoritesOnly = false @Published var landmarks = landmarkData } objectWillChange
  • 21.
    ObservableObject - @ObservedObject structLandmarkList: View { @ObservedObject var userData: UserData var body: some View { NavigationView { List { Toggle(isOn: $userData.showFavoritesOnly) { Text("Show Favorites Only") } ForEach(userData.landmarks) { landmark in if !self.userData.showFavoritesOnly || landmark.isFavorite { // ~~~~ } } } .navigationBarTitle(Text("Landmarks")) } } } LandmarkList(userData: UserData())
  • 22.
    EnvironmentObject - .environmentObject(_) //SceneDelegate let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: LandmarkList() .environmentObject(UserData())) self.window = window window.makeKeyAndVisible()
  • 23.
    EnvironmentObject - @EnvironmentObject structLandmarkList: View { @EnvironmentObject private var userData: UserData var body: some View { NavigationView { List { Toggle(isOn: $userData.showFavoritesOnly) { Text("Show Favorites Only”) } ForEach(userData.landmarks) { landmark in if !self.userData.showFavoritesOnly || landmark.isFavorite { // ~~~ } } } .navigationBarTitle(Text("Landmarks")) } } }
  • 24.
  • 25.
  • 26.
    . 1. . -single source of truth 2. State source of truth , view function of state . 3. @State framework view change , @Binding souce of truth reference 4. @ObservedObject dependency , @EnvironmentObject view dependency
  • 27.
    Reference. - SwiftUI byTutorials (Raywenderlich) - Data Flow Through SwiftUI (WWDC 2019) - SwiftUI Essential : Handling User Input - Data in SwiftUI, Part 1: Data - Single Source of Truth - Wikipedia