Mekal Z

Mekal Z

A programmer running out of the wall.
twitter

SwiftUI:@ObservedObject 與 @StateObject 之間的差異

基礎#

在 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 生成的頭像。她非常喜歡。

linguatale_appicon.png

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。