基礎#
在 SwiftUI 中,@ObservedObject 和 @StateObject 都是用來管理視圖中物件狀態的屬性包裝器。
@ObservedObject 用於標記 ObservableObject 協議的物件,作為當前視圖所觀察的物件。這意味著當 @ObservableObject 標記的物件狀態發生變化時,視圖會自動刷新。通常,@ObservedObject 用於在視圖之間共享狀態。
例如,假設有一個符合 ObservableObject 協議的 UserSettings 類,用於存儲用戶偏好設置。
class UserSettings: ObservableObject {
@Published var theme: Theme = .light
}
我們可以在視圖中使用 @ObservedObject 屬性包裝器來觀察 UserSetting 物件,如下所示:
struct SettingsView: View {
@ObservedObject var userSettings = UserSettings()
var body: some View {
// ...
}
}
在這個例子中,當用戶更改偏好設置時,UserSettings 的 @Published 屬性將會被更新,SettingsView 將自動刷新。
另一方面,@StateObject 標記符合 ObservableObject 協議的物件,作為當前視圖擁有的狀態物件。這意味著當 @StateObject 標記的物件發生變化時,只會影響擁有該物件的視圖。通常,@StateObject 用於在單個視圖中管理狀態。
例如,假設有一個符合 ObservableObject 的 TimerModel 類,用於管理計時器的狀態。
class TimerModel: ObservableObject {
@Published var time: Double = 0
init() {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.time += 1
}
}
}
我們可以使用 @StateObject 創建一個擁有 TimerModel 的狀態變數,如下所示。
struct TimerView: View {
@StateObject var timerModel = TimerModel()
var body: some View {
Text("\(timerModel.time)")
}
}
在這個例子中,只有 TimerView 會受到 TimerModel 物件的 @Published 屬性變化的影響。其他視圖不會收到任何更新。
真正的區別#
在前面的例子中,並沒有明顯的區別。那麼為什麼用 @StateObject 包裝的物件只影響當前視圖呢?
在上面的例子中,確實沒有太大的區別。但當 @ObservableObject 的物件被其父視圖傳遞到兩個視圖時,將會有顯著的區別。
當我們在視圖中使用 @StateObject 創建物件的實例時,該實例將與視圖擁有相同的生命週期,這意味著當視圖被銷毀時,它也會被銷毀。
因此,使用 @StateObject 包裝的物件將僅存在於當前視圖中,並且只會影響當前視圖。如果其他視圖需要相同的物件,則應使用 @ObservedObject 包裝器。
在上面的例子中,我們使用 @StateObject 包裝器創建了一個 TimerModel 實例,並將其存儲在 timerModel 的屬性中。因此,物件 timerModel 只存在於 TimerView 中,其他視圖無法訪問。
以下是一個 ObservableObject 的物件被多個視圖觀察的例子。
class UserSettings: ObservableObject {
@Published var theme: Theme = .light
}
struct SettingsView: View {
@ObservedObject var userSettings: UserSettings
var body: some View {
VStack {
Text("設置視圖")
Text("當前主題: \(userSettings.theme.rawValue)")
}
}
}
struct ProfileView: View {
@ObservedObject var userSettings: UserSettings
var body: some View {
VStack {
Text("個人資料視圖")
Text("當前主題: \(userSettings.theme.rawValue)")
}
}
}
struct ContentView: View {
@StateObject var userSettings = UserSettings()
var body: some View {
VStack {
SettingsView(userSettings: userSettings)
ProfileView(userSettings: userSettings)
}
}
}
在這個例子中,當用戶更新 userSettings 的主題屬性時,SettingsView 和 ProfileView 將自動更新並顯示最新的主題。這是多個視圖觀察同一個 ObservableObject 協議物件的基本實現。
如果我們在 SettingsView 或 ProfileView 中使用 @StateObject,則就像我們將參數傳遞到兩個視圖中,它們各自在自己的上下文中創建了一個副本。在這種情況下,狀態變化將被限制在各自的上下文中,並且不會相互影響。
分享一張圖片作為帖子封面
這是我昨天為 Jaina 生成的頭像。她非常喜歡。