ObservableObject + @Published vs objectWillChange.send()

问题描述 投票:0回答:1

我在使用

@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

谢谢

swift swiftui observable
1个回答
0
投票

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
属性的方式存在问题。

© www.soinside.com 2019 - 2024. All rights reserved.