我在使用
@ObservedObject
和 @Published
时观察到了奇怪的模式。SwiftUI
视图中,但视图似乎在对象的实际更改之前刷新。
所以当我检查它的 @ObservedObject
属性时,我的
@Published
没有正确的值。如果我添加
didSet
和
objectWillChange.send()
,它会按预期工作。这是我正在使用的代码:
class AuthManager: ObservableObject {
@Published public private(set) var user: User {
willSet { print("Will set") }
didSet { print("Did set") }
}
}
struct AuthView: View {
@ObservedObject var authManager: AuthManager
var body: some View {
let _ = Self._printChanges()
print("AuthManager user = \(authManager.user)")
return (
Text("AuthManager Test")
)
}
}
当我在 AuthManager 中更新用户对象时,我按以下顺序获取日志:
Will set
AuthView: @self, @identity, _authManager
AuthManager user = xxx // <-- old version
Did set
如果我删除 @Published
并触发
objectWillChange.send()
中的
didSet
,该行为将按预期工作。我希望在视图刷新时获得新版本。 我是否遗漏了什么,或者有什么我不明白的关于
ObservableObject
和
@Published
?谢谢
objectWillChange
的
ObservableObject
发布者始终在
willSet
处理程序中发出新事件:
具有发布者的对象类型,在对象更改之前发出。参见
官方文档。
因此,您在这方面观察到的行为是正常的。如果更改
Published
属性的值,则会计划新的布局过程,但不会直接执行。这使得所有更改能够首先收集并在下一个布局过程中一起应用。采用以下示例,对您的代码稍作修改,您将看到输出与预期一致:
@MainActor
final class ContentViewModel: ObservableObject {
@Published var myValue = ""
}
var counter = 0
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
var body: some View {
let _ = Self._printChanges()
let _ = print("myValue = \(viewModel.myValue)")
VStack {
Text(viewModel.myValue)
Button("Change Value") {
counter += 1
viewModel.myValue = "Greetings \(counter)!"
}
}
.padding()
}
}
按下按钮后的输出将是:
ContentView: _viewModel changed.
myValue = Greetings 1!
您在代码中没有向我们展示的是如何更改 user
的
AuthManager
值。有很多因素可能会导致您所描述的问题。例如,如果您不更改主线程中的值。请注意我如何将示例中的
ContentViewModel
绑定到
MainActor
。您的日志输出也很不寻常。更改
user
属性不应导致视图结构标识的更改,您实际应该看到的唯一日志输出是:
AuthView: _authManager changed.
@self
和
@identity
不应包含在日志输出中。因此,此输出表明您的父视图、
AuthView
的另一个周围视图或您更改
Published
属性的方式存在问题。