SwiftUI状态管理@State/@Binding/@ObservedObject/@EnvironmentObject/@StateObject

视频教程:3-2 常用的属性包装:State、Binding、Environment 介绍 - Swift 新手入门_哔哩哔哩_bilibili

@State

基本描述:

和一般的存储属性不同,@State 修饰的值,在 SwiftUI 内部会被自动转换为一对 setter 和 getter,对这个属性进行赋值的操作将会触发 View 的刷新,它的 body 会被再次调用,底层渲染引擎会找出界面上被改变的部分,根据新的属性值计算出新的 View,并进行刷新。

使用示例:

Swift 复制代码
struct ContentView: View {
    @State var count = 0
    var body: some View {
        VStack{
            Text(count)
            Button("点击+1") {
                count+=1
            }
            .background(.orange)
        }
    }
}

结果描述:通过@State定义变量count,点击按钮会触发Text中数字的显示

@Binding

基本描述:

和 @State 类似,@Binding 也是对属性的修饰,它做的事情是将值语义的属性"转换"为引用语义。对被声明为 @Binding 的属性进行赋值,改变的将不是属性本身,而是它的引用,这个改变将被向外传递.

使用示例:

Swift 复制代码
struct ContentView: View {
    @State var count = "eeer"
    var body: some View {
        VStack{
           
            MapView(count1: $count)
        }
        Text(count)
            .padding()
    }
}
struct MapView: View{
  @Binding  var count1: String
    var body: some View {
          Button("点我") { //添加一个按钮,指定标题文字为 First button
          self.count1 = "1234567890"
       }
    }
}

结果描述:使用@state可以实现在当前view视图内的状态管理,但是如果需要将状态传递到子视图,并且实现双向绑定就需要使用@Binding来实现,示例中通过@Binding绑定上层传递过来的count1,当点击按钮后,会发现最上层view的Text内容变成了1234567890,这里就实现了双向绑定,并且通过@Binding绑定的数据或者对象其生命周期同MapView保存一致

@ObservedObject

基本描述:

如果说 @State 是全自动驾驶的话,ObservableObject 就是半自动,它需要一些额外的声明。ObservableObject 协议要求实现类型是 class,它只有一个需要实现的属性:objectWillChange。在数据将要发生改变时,这个属性用来向外进行"广播",它的订阅者 (一般是 View 相关的逻辑) 在收到通知后,对 View 进行刷新。

创建 ObservableObject 后,实际在 View 里使用时,我们需要将它声明为 @ObservedObject。这也是一个属性包装,它负责通过订阅 objectWillChange 这个"广播",将具体管理数据的 ObservableObject 和当前的 View 关联起来。

使用示例:

Swift 复制代码
class Person:ObservableObject{
    @Published var name = "张三"
}

struct ContentView: View {
    @ObservedObject var p = Person()
    var body: some View {
        VStack{
            Text(p.name)
                .padding()
            Button("点我") { //添加一个按钮,指定标题文字为 First button
                p.name = "1234567890"
         }
        }
    }
}

@ObservedObject修饰的必须是遵守ObservableObject 协议的class对象
class对象的属性只有被@Published修饰时,属性的值修改时,才能被监听到

@EnvironmentObject

基本描述:

在 SwiftUI 中,View 提供了 environmentObject(_😃 方法,来把某个 ObservableObject 的值注入到当前 View 层级及其子层级中去。在这个 View 的子层级中,可以使用 @EnvironmentObject 来直接获取这个绑定的环境值。

使用示例

Swift 复制代码
final class Person:ObservableObject{
  @Published var name = "测试测试测试测试测试测试"
   
}
struct ContentView: View {
    var body: some View {
        VStack{
            let p = Person()
            MapView().environmentObject(p)
        }
    }
}

struct MapView: View {
    @EnvironmentObject var p:Person
    var body: some View {
        VStack{
            Text(p.name)
            Button("点我") { //添加一个按钮,指定标题文字为 First button
                p.name = "1234567890"
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
     
        ContentView()
    }
}

@EnvironmentObject 修饰器是针对全局环境的。通过它,我们可以避免在初始 View 时创建 ObservableObject, 而是从环境中获取 ObservableObject

可以看出我们获取 p这个 ObservableObject 是通过 @EnvironmentObject 修饰器,但是在入口需要传入 .environmentObject(p) 。@EnvironmentObject 的工作方式是在 Environment 查找 Person 实例。

@StateObject

基本描述:

StateObject行为类似ObservedObject对象,区别是StateObject由SwiftUI负责针对一个指定的View,创建和管理一个实例对象,不管多少次View更新,都能够使用本地对象数据而不丢失

使用示例:

Swift 复制代码
import SwiftUI
final class Person:ObservableObject{
  @Published  var name = "测试"
    deinit{
        print("销毁")
    }
}
struct ContentView: View {
    @StateObject var p = Person()
    var body: some View {
        VStack{
            Text(p.name)
            Button("点击"){
                  p.name = "哈哈哈"
            }
           
        }
    }
}

@StateObject和@ObservedObject区别

1、@ObservedObject只是作为View的数据依赖,不被View持有,View更新时ObservedObject对象可能会被销毁

适合数据在SwiftUI外部存储,把@ObservedObject包裹的数据作为视图的依赖,比如数据库中存储的数据`

2、针对引用类型设计,当View更新时,实例不会被销毁,与State类似,使得View本身拥有数据

示例1

Swift 复制代码
import SwiftUI
final class Person:ObservableObject{
  @Published  var name = 1
    deinit{
        print("销毁")
    }
}

struct ContentView: View {
    @State var count = 0
    var body: some View {
        VStack{
            Text("刷新CounterView计数 :\(count)")
                       Button("刷新"){
                           count += 1
            }
           MapView()
        }
    }
}

struct MapView: View {
    @ObservedObject var p = Person()
    var body: some View {
        VStack{
            Text("\(p.name)")
            Button("+1") { //添加一个按钮,指定标题文字为 First button
                p.name += 1
            }

        }
    }
}

点击刷新时,Person 的deinit方法被调用,说明p对象被销毁;

先连续点击+1,Text上的数字在一直递增,当点击刷新时Text上的数字恢复为1,这个现象也说明p对象被销毁

示例2

Swift 复制代码
import SwiftUI
final class Person:ObservableObject{
  @Published  var name = 1
    deinit{
        print("销毁")
    }
}

struct ContentView: View {
    @State var count = 0
    var body: some View {
        VStack{
            Text("刷新CounterView计数 :\(count)")
                       Button("刷新"){
                           count += 1
            }
           MapView()
        }
    }
}

struct MapView: View {
    @StateObject var p = Person()
    var body: some View {
        VStack{
            Text("\(p.name)")
            Button("+1") { //添加一个按钮,指定标题文字为 First button
                p.name += 1
            }

        }
    }
}

和例1不同的是怎么操作,p都不会销毁

总结

@StateObject的声明周期与当前所在View生命周期保持一致,即当View被销毁后,StateObject的数据销毁,当View被刷新时,StateObject的数据会保持;而ObservedObject不被View持有,生命周期不一定与View一致,即数据可能被保持或者销毁;

相关推荐
黑化旺仔13 小时前
【OC】Runtime:类元数据、加载初始化与消息派发
开发语言·macos·ios·objective-c
songgeb14 小时前
iOS App支持设置RTL语言的实践
ios·swift·ui kit
软泡芙14 小时前
【iOS】swift启动屏显示黑屏
ios
用户693717500138416 小时前
当你向领导申请 AI 编程工具预算时,如果领导追问“能提效多少,有量化数据吗”,你该怎么回答?
android·后端·ios
Layer16 小时前
一些脱离 Mac 依赖的 Agent 操作 iPhone 实现
ios·ai编程·测试
用户693717500138418 小时前
当我说 Claude 搭配 GLM-5.3-Flash 太好用了,同事却提醒我:你可能正在失去对代码的掌控
android·后端·ios
茶底世界之下18 小时前
一键裁方会丢掉什么?用 Awaking 给园林照片做两种画幅
ios
Marco_Marco13519 小时前
定位SDK接入实战:Android/iOS/鸿蒙三端怎么选、怎么接
android·ios·harmonyos
老李IT笔记1 天前
关掉设备上的 AI 扩展:两个键各管一层,配错了等于没配
人工智能·ios·智能手机
2501_915921431 天前
iOS应用耗电测试:使用Energy Log、Keymob和Instruments进行性能监控与能源消耗分析
android·ios·小程序·https·uni-app·iphone·webview