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)")
    }
}

在这个例子中,当 TimerModel 对象的 @Published 属性发生变化时,只有 TimerView 会受到影响。其他视图不会收到任何更新。

真正的区别#

在前面的例子中没有明确的区别。那么为什么用 @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

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。