Bootstrap

SwiftUI中@State @StateObject @ObservedObject @EnvironmentObject定义和使用场景区别

在 SwiftUI 中,@State、@StateObject、@ObservedObject 和 @EnvironmentObject 是用于管理和共享数据的四个重要属性包装器(property wrappers)。它们各自有不同的使用场景和特性。下面是对它们的详细介绍。

1. @State

@State 用于管理视图内部的值类型的数据状态,使用最多的的一个类型。当状态发生变化时,SwiftUI 会自动重新渲染相关的视图。

使用场景:适用于简单的、局部的状态管理。只在定义它的视图内部使用。

示例代码:

struct CounterView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button(action: {
                count += 1
            }) {
                Text("Increment")
            }
        }
    }
}

2. @StateObject

@StateObject 用于管理自己本视图的 ObservableObject 状态对象。它负责创建和持有一个 ObservableObject 实例。当对象的属性发生变化时,SwiftUI 会自动更新使用该对象的视图。@Published用于声明该属性是可以被观察的,如果没有声明这个属性包装器,那么这个属性的变化就会被忽视。

使用场景:

适用于需要在视图内创建和管理的复杂对象。
确保对象在视图生命周期内被持有。

示例代码:

class CounterModel: ObservableObject {
    @Published var count = 0
}

struct CounterView: View {
    @StateObject private var counter = CounterModel()

    var body: some View {
        VStack {
            Text("Count: \(counter.count)")
            Button(action: {
                counter.count += 1
            }) {
                Text("Increment")
            }
        }
    }
}

3. @ObservedObject

@ObservedObject 用于引用由其他视图或外部管理的 ObservableObject 实例,比如在子视图里面声明一个@ObservedObject变量,然后通过父视图传递进来。它不会创建或持有对象,只是观察对象的变化并更新视图。@Published用于声明该属性是可以被观察的,如果没有声明这个属性包装器,那么这个属性的变化就会被忽视。

使用场景:

适用于视图间共享的状态对象。
不负责对象的生命周期管理。

示例代码:

class CounterModel: ObservableObject {
    @Published var count = 0
}

struct CounterView: View {
    // 子视图声明counter变量,并使用@ObservedObject属性包装器声明
    @ObservedObject var counter: CounterModel

    var body: some View {
        VStack {
            Text("Count: \(counter.count)")
            Button(action: {
                counter.count += 1
            }) {
                Text("Increment")
            }
        }
    }
}

// 使用示例
struct ContentView: View {
    // 父视图声明@StateObject 变量counter
    @StateObject private var counter = CounterModel()

    var body: some View {
        // 传递给子视图
        CounterView(counter: counter)
    }
}

4. @EnvironmentObject

@EnvironmentObject 用于在视图层次结构中共享对象。被标记为 @EnvironmentObject 的对象可以在整个视图层次结构中注入和访问,而无需显式地传递它。

使用场景:

适用于跨多个视图共享的全局状态。
必须在视图层次结构的根视图中使用 .environmentObject() 注入对象。

示例代码:

class CounterModel: ObservableObject {
    @Published var count = 0
}

struct CounterView: View {
    @EnvironmentObject var counter: CounterModel

    var body: some View {
        VStack {
            Text("Count: \(counter.count)")
            Button(action: {
                counter.count += 1
            }) {
                Text("Increment")
            }
        }
    }
}

// 使用示例
struct ContentView: View {
    @StateObject private var counter = CounterModel()

    var body: some View {
        CounterView()
            .environmentObject(counter)
    }
}

总结

@State:管理视图内部的简单值类型状态。

@StateObject:管理视图内部创建和持有的复杂状态对象。

@ObservedObject:观察并响应由外部或其他视图管理的状态对象的变化,一般是父视图传递给子视图里面的属性,就像@Binding。

@EnvironmentObject:在视图层次结构中共享全局状态对象。

理解这四种属性包装器的用途和区别,有助于在 SwiftUI 开发中有效地管理和共享状态。 

;