点击按钮时更改视图的视图模型会导致:"AttributeGraph: cycle detected through attribute warning"



我做了一个简单的Playground示例,试图找出如何将视图模型连接到视图与SwiftUI和组合。我相信我已经按照书上的方法做了(查看下面的代码示例),但是当我点击"增量"时;按钮此打印出现在控制台中:

=== AttributeGraph: cycle detected through attribute 22736 ===
=== AttributeGraph: cycle detected through attribute 18320 ===
=== AttributeGraph: cycle detected through attribute 17200 ===
=== AttributeGraph: cycle detected through attribute 18320 ===
=== AttributeGraph: cycle detected through attribute 21592 ===
=== AttributeGraph: cycle detected through attribute 21592 ===
=== AttributeGraph: cycle detected through attribute 21768 ===
=== AttributeGraph: cycle detected through attribute 21768 ===
=== AttributeGraph: cycle detected through attribute 18152 ===
=== AttributeGraph: cycle detected through attribute 21768 ===
=== AttributeGraph: cycle detected through attribute 20224 ===
=== AttributeGraph: cycle detected through attribute 18152 ===
=== AttributeGraph: cycle detected through attribute 18152 ===
=== AttributeGraph: cycle detected through attribute 18280 ===
=== AttributeGraph: cycle detected through attribute 22568 ===
=== AttributeGraph: cycle detected through attribute 22568 ===
=== AttributeGraph: cycle detected through attribute 22736 ===
=== AttributeGraph: cycle detected through attribute 22568 ===
=== AttributeGraph: cycle detected through attribute 22736 ===
=== AttributeGraph: cycle detected through attribute 22568 ===

之后,我开始对代码进行实验,并认为延迟调用视图模型的增量方法可以解决这个问题。(取消注释示例中的注释行来测试这一点。)现在困扰我的是,我不知道为什么会发生这个警告,或者为什么延迟方法调用来修复它。

如果有人能解释一下幕后发生了什么以及为什么会发生这种情况,我将不胜感激。

环境:

macOS Big Sur Version 11.4
Xcode Version 12.5.1 (12E507)

示例代码:

import Combine
import SwiftUI
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class ViewModel: ObservableObject {
@Published private (set) var counter: Int = 0

func increment() {
counter += 1
}
}
struct SomeView: View {
@ObservedObject var viewModel: ViewModel

var body: some View {
VStack(alignment: .center, spacing: 8) {
Text("Counter: (viewModel.counter)")
.padding()
Button("Increment") {
// uncomment to fix AttributeGraph cycle warning
//                DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
self.viewModel.increment()
//                }
}
.padding()
}
.padding()
}
}
let viewModel = ViewModel()
let view = SomeView(viewModel: viewModel)
PlaygroundPage.current.setLiveView(view)

我不熟悉Playground,但在应用程序中,我会使用:

@StateObject viewModel = ViewModel()

let viewModel = ViewModel()

和如果需要在SomeView:

DispatchQueue.main.async {
self.viewModel.increment()
}

最新更新