@StateObject 修饰的对象与 @ObservedObject 一样,都需要遵循 Observable 协议,功能也类似。区别在于,@StateObject 修饰的对象只会在所属的 View 中创建一次并在 View 的生命周期内存储相应的状态,而 @ObservedObject 修饰的对象会随着 View 的重绘生成新的对象,不会在 View 的生命周期内存储该对象的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| import SwiftUI
class Counter: ObservableObject { @Published var count: Int = 0 } struct StateObjectDemo: View { @State private var buttonTitle = "Tap me" var body: some View { ItemList() } } struct ItemList: View { @State private var items = ["hello", "world"] var body: some View { VStack { Button("Append item to list") { items.append("test") } List(items, id: \.self) { name in Text(name) } CounterView1() CounterView2() } } }
struct CounterView1: View { // StateObject示例 @StateObject var counter1 = Counter() var body: some View { VStack { Text("StateObject count: \(counter1.count)") Button("点击StateObject➕1") { counter1.count += 1 } } } }
struct CounterView2: View { // ObservedObject示例 @ObservedObject var counter2 = Counter() var body: some View { VStack { Text("ObservedObject count: \(counter2.count)") Button("点击ObservedObject➕1") { counter2.count += 1 } } } }
struct StateObjectDemo_Previews: PreviewProvider { static var previews: some View { StateObjectDemo() } }
|
如上代码所示,当我们点击 CounterView1 和 CounterView2 中的按钮时,会给相应的 Counter 实例的 count 属性加 1,一旦我们点击 “Append item to list” 按钮,View 会执行重绘,这时 CounterView2 中的 count 会重置为 0,而 CounterView1 中使用 @StateObject 修饰的对象中的 count 仍然持有当前的数据状态。
那么我们应该在什么场景下分别使用这两个属性包装器呢?
在 View 的生命周期内,需要一直持有并存储对象的状态时,使用 @StateObject 修饰。基本上,绝大多数情况下的 viewModel 都会是这种情况。
只有在少数情况下,View 不需要一直持有该对象,该对象的状态会随着外界的条件改变而刷新自己时,我们才用到 @ObservedObject 修饰,比如上面的例子,如果我们要求点击 “Append item to list” 按钮时,count 就重置,就需要用 @ObservedObject 修饰了。