🔸observable object
SwiftUI ⟩ view ⟩ state ⟩ observable object
An observable object is an object of any class type that conforms to the ObservableObject protocol, any changes to its published values will cause all views using those values to automatically update, reflecting the changes.
// ⭐️ 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?