🅿️ObservableObject
SwiftUI ⟩ Data Flow ⟩ ObservableObject
// ⭐️ 1. declare an observable object type
final class ModelData: ObservableObject {
// ⭐️ 2. declare published properties
@Published var landmarks: [Landmark] = load("landmarkData.json")
}
// app
struct LandmarksApp: App {
// ⭐️ 3. initialize an observable object (data model)
@StateObject private var modelData = ModelData()
var body: some Scene {
WindowGroup {
ContentView()
// ⭐️ 4. put the model object in the environment.
// ------------------------------------------------
// any subview can access this model object
// through `@EnvironmentObject` automatically. (see 6.)
.environmentObject(modelData)
}
}
}
// any subview in the view hierarchy
struct LandmarkList: View {
// ⭐️ 5. adopt the model object as an `@EnvironmentObject`
// --------------------------------------------------------
// `modelData` property gets its value AUTOMATICALLY, as long as
// `environmentObject(_:)` modifier has been applied to a parent view.
@EnvironmentObject var modelData: ModelData
var body: some View { ... }
}An observable object is a custom object (reference type) for your data that can be bound to a view from storage in SwiftUI’s environment.
Use ObservableObject to declare an observable object type.
Use @Published to declare published values in an observable object type.
Use @StateObject to initialize an observable object.
data model:data shared with any views in your app.
environment object:an observable object, which is put in the environment by calling an ancester view's .environmentObject(_:) modifier.
Combine ⟩ ObservableObject (protocol)
SwiftUI ⟩ Model data ⟩ @ObservedObject (property wrapper)
SwiftUI Tutorials ⟩ Handling User Input ⟩
問題
在跟 CS193P 到第三課的時候,如果按照課程上的程式碼原封不動的照抄,程式可以正常執行。
但如果擅自將 Card 這個 struct 改成不僅遵循 Identifiable 同時也遵循 Equatable,這時就出現問題了:「在按卡片的時候,卡片不會翻面」,這問題似乎跟 ForEach(data){ ... } 語法裡面,data 部分的 .id 有關係。
就算 @Published var viewModel 更新了,但在 ForEach(viewModel.cards) 裡面的 cards 的 id 並沒有變更,再加上 Card 本身遵循 Equatable (這點很重要,因為如果沒有 Equatable,程式可正常執行),造成 SwiftUI 判斷 EmojiMemoryGameView 的 body 裡面的 ForEach 部分不需更新,因此就不會翻面了。
有 Equatable 跟沒有 Equatable 怎麼差那麼多呢?SwiftUI 是如何判斷一個 view 到底要不要更新呢?
參考資料
Swift ⟩ Standard Library ⟩ Basic Behaviors ⟩ Identifiable
Last updated
Was this helpful?