在点击按钮时更改视图的 ViewModel 会导致:“AttributeGraph:通过属性警告检测到循环”

Posted

技术标签:

【中文标题】在点击按钮时更改视图的 ViewModel 会导致:“AttributeGraph:通过属性警告检测到循环”【英文标题】:Changing View's ViewModel on button tap causes: "AttributeGraph: cycle detected through attribute warning" 【发布时间】:2021-08-03 11:39:00 【问题描述】:

我做了一个简单的 Playground 示例,试图弄清楚如何使用 SwiftUI 和 Combine 将 View Model 连接到 View。 我相信我已经按书完成了(检查下面的代码示例),但是当我点击“增量”按钮时,此打印出现在控制台中:

 === 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 ===

在那之后,我开始试验代码并发现延迟调用 View Model 的增量方法可以解决这个问题。 (取消注释示例中的注释行以对此进行测试。) 现在困扰我的是,我不知道为什么会出现这个警告,也不知道为什么延迟方法调用会修复它。

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

环境:

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)

【问题讨论】:

这不会发生在 xcode 或 iPhone 中。 【参考方案1】:

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

 @StateObject viewModel = ViewModel()

不是

 let viewModel = ViewModel()

如果需要在 SomeView 中:

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

【讨论】:

以上是关于在点击按钮时更改视图的 ViewModel 会导致:“AttributeGraph:通过属性警告检测到循环”的主要内容,如果未能解决你的问题,请参考以下文章

WPF 在 ViewModel.PropertyChanged 事件上更改按钮内容

TableView 单元格重用导致按钮标题在滚动时更改

点击 3 次时如何更改导航按钮的图像?

点击单元格内的按钮时如何显示更改?

我如何使用视图模型从另一个片段访问函数

点击时更改按钮的文本颜色