SwiftUI 属性包装器系列 --- @StateObject @ObservedObject @Published

@Published

@Published 是 SwiftUI 中的属性包装器之一,它允许我们创建可观察的对象,并且在发生更改时触发视图重绘。我们经常将@Published与ObservableObject协议结合使用。

SwiftUI 会自动监视此类更改,body里面依赖于该属性的数据的任何视图将重新调用已达到更新视图的目的。

实际上,这意味着每当标记@Published属性的对象发生更改时,使用该对象的所有视图都将重新更新以体现这些更改。

kotlin 复制代码
class ArticleViewModel: ObservableObject {
    @Published
    var title: String = "An example title"
}
struct ArticleView: View {
  @StateObject private var article = ArticleViewModel()
  var body: some View {
    Text("provider value: (article.title)")
  }
}

这符合ObservableObject协议,这意味着 SwiftUI 的视图可以观察它的变化。

kotlin 复制代码
class ArticleViewModel: ObservableObject {
    var title: String = "An example title"
}
struct ArticleView: View {
  @StateObject private var article = ArticleViewModel()
  var body: some View {
    Text("provider value: (article.title)")
  }
}

因为ArticleViewModel唯一的属性没有标记为@Published,所以不会发送任何更改的通知。这意味着数据已经发生了变更,但是不会更新任何视图。

注意事项: 包装器是类约束的,这意味着您只能在类的实例上使用它。在结构体内部使用时会出现错误:

@Published 属性包装器是类约束的,并且仅适用于类的属性。

@Published 属性包装器的包装值表示属性的实际值:

为什么 willSet 而不是 didSet?

@Published属性包装器有效地将title属性观察器添加到willSet,以便任何更改都会自动发送给观察者。

SwiftUI 需要在旧状态和新状态之间进行比较,以决定是否需要重新渲染视图。为此,需要有旧状态的引用,这就是@Published使用 willSet 的原因。

objectWillChange

ObservableObject是一种特殊的协议,它将合成了一个objectWillChange发布者,当其包含的任何 @Published 属性发生更改时,该发布者会发出消息。

csharp 复制代码
let viewModel = ArticleViewModel()
viewModel.objectWillChange.sink { _ in
    print("Articles view model changed!")
}

viewModel.title = "@Published explained"
// Prints:
// Articles view model changed!

SwiftUI Published使用objectWillChange重绘其视图以响应任何更改。

@StateObject

@StateObject属性包装器与类似@State,只不过它适用于ObservableObject。一个ObservableObject始终是引用类型 (class),并且每当其@Published属性之一发生更改时都会通知。

kotlin 复制代码
class DataProvider: ObservableObject {
  @Published var currentValue = "a value"
}

struct DataOwnerView: View {
  @StateObject private var provider = DataProvider()
  var body: some View {
    Text("provider value: (provider.currentValue)")
  }
}

代码解释: DataOwnerView创建了一个DataProvider的实例。每当值发生DataProvider.currentValue变化时,DataOwnerView就会重新渲染。每当 SwiftUI 决定放弃并重新创建DataOwnerView新的渲染时,SwiftUI 都会保留最初创建DataProvider的实例。这意味着@StateObject仅初始化一次。

换句话说,标记为@StateObject的属性就会保留其最初分配的实例,即使 SwiftUI 重新创建了结构体。 这与您在@State中看到的行为相同,只不过它应用于一个ObservableObject的类型而不是一个struct值类型。

注意事项

  • 响应ObservableObject的类型.
  • 正在使用@StateObject的视图创建其自身的实例。

@ObservedObject

SwiftUI 为我们提供了@ObservedObject属性包装器,以便视图可以观察外部对象的状态,并在重要内容发生变化时收到通知。

@ObservedObject属性包装器 类似@Binding类似,@ObservedObject也是仅使用从其他地方传入的视图,

swift 复制代码
struct DataOwnerView: View {
  @StateObject private var provider = DataProvider()
  var body: some View {
    VStack {
      Text("provider value: (provider.currentValue)")
      DataUserView(provider: provider)
    }
  }
}

struct DataUserView: View {
  @ObservedObject var provider: DataProvider
  var body: some View {
    // create body and use / modify `provider`
  }
}

注意事项:

  • 响应ObservedObject.
  • 视图不会创建其自身的ObservedObject实例。(如果是这样,您需要一个@StateObject)
相关推荐
songgeb1 天前
YYImage Bug:一行之差,正常 JPEG 如何在 iOS 被读成条纹
ios·swift
fthux1 天前
Tick Rest,一个休息提醒工具的自我修养
macos·开源·swift
Fatbobman(东坡肘子)2 天前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift
chaoahyl2 天前
WaterDiary 喝水记录 App 实战(2)· 实现喝水首页与本地保存
swift
茶底世界之下3 天前
iPhone Duo 适配实战,Awaking 踩过的 8 个坑
ios·swiftui·swift
xbzb3 天前
Swift 对象存储建环实验 + Ceilometer 计量:两个收尾服务
swift·ring·实验·ceilometer·象存储·建环
2501_916008893 天前
iOS App 图标、启动屏和多语言搭配 方法,上架前使用KXBuild一次做好 App 图标
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_915918413 天前
iOS 推送通知怎么实现,从 APNs p8 密钥到 iOS 真机收到第一条推送
vscode·ios·objective-c·个人开发·swift·敏捷流程
东坡肘子3 天前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
人工智能·swiftui·swift
2501_916007475 天前
Windows OpenSSL 生成 iOS 证书,制作 p12 与描述文件,KXBuild 签名实操
windows·vscode·ios·objective-c·个人开发·swift·敏捷流程