← 返回首頁
Flo writes Code
Flo writes Code
@FloWritesCode
𝕏 (Twitter)🔥🔥🔥
AI 中文摘要Claude 生成

停止使用 ObservableObject

ObservableObject 會引入副作用和效能問題,但有替代方案。

ObservableObject 曾經是為 SwiftUI View 建構 ViewModels 和其他 data sources 的「唯一」解決方案。多年來,主要問題是該使用哪種 PropertyWrapper:ObservedObject、StateObject 還是 EnvironmentObject。無論您選擇哪種方法,它們都依賴於 Combine 進行 View updates——您的 ObservableObject 會有一個 objectWillChangeobject,其型別為 ObjectWillChangePublisher,用於通知 View 任何 @.Published 屬性變更。

問題所在

一如往常,魔鬼藏在細節裡:這個 publisher 每次都會在任何 published 屬性變更時觸發——無論 View 是否依賴於該屬性。在許多簡單的使用情境中,這可能不重要。但一旦您將 View 分解成更小的 Subviews,或開始在多個 View 之間共享 ObservableObject,事情就會開始變得棘手:如果 View 不必要地重繪,就會出現明顯的效能問題。所有這些都發生了,因為 ObservableObject 是透過 Combine framework 建構(並連接到您的 View)的。

解決方案

首先:如果您的 app 需要支援 iOS 17 之前的版本(或嚴重依賴於 Combine pipelines 來處理您的 published properties),您可以停止閱讀這篇文章,因為我們即將探討的 framework 就是在那個時候引入的。它叫做 Observation,是 ObservableObject 的(幾乎)直接繼承者。這個 framework 包含一個新的 @.Observable macro,您可以將其附加到 Swift class。

// Old approach
import SwiftUI

class ViewModel: ObservableObject {
  @Published var username: String = ""
}

// New approach
import SwiftUI
import Observation

@Observable
class ViewModel {
  var username: String = ""
}

如果您對細節很敏銳,您會注意到一個根本性變革:Implicit State。過去您需要明確標記屬性為 @.Published。任何未標記的屬性都不會更新 View。但有了 Observation,任何屬性都會更新。您可以透過附加 @.ObservationIgnored macro 將屬性標記為不更新。

我在本文開頭討論了不同的 PropertyWrappers,用於將 ObservableObject 附加到 View。這些不適用於 @.Observable class。相反地,您將只使用 @.State 來處理此 View 所擁有的 class,以及使用 @.Bindable 或 @.Environment 來處理另一個 View 所擁有的 class。