🅿️ObservableObject

SwiftUIData 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.

問題

在跟 CS193P 到第三課的時候,如果按照課程上的程式碼原封不動的照抄,程式可以正常執行。

但如果擅自將 Card 這個 struct 改成不僅遵循 Identifiable 同時也遵循 Equatable,這時就出現問題了:「在按卡片的時候,卡片不會翻面」,這問題似乎跟 ForEach(data){ ... } 語法裡面,data 部分的 .id 有關係。

就算 @Published var viewModel 更新了,但在 ForEach(viewModel.cards) 裡面的 cardsid 並沒有變更,再加上 Card 本身遵循 Equatable (這點很重要,因為如果沒有 Equatable,程式可正常執行),造成 SwiftUI 判斷 EmojiMemoryGameView 的 body 裡面的 ForEach 部分不需更新,因此就不會翻面了。

參考資料

Last updated

Was this helpful?