@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
)