Firebase实时数据库数据累加至本地变量时遇buildExpression匹配错误
SwiftUI中累加Double变量触发
buildExpression匹配错误的解决方法 问题描述
尝试将Firebase实时数据库中的数据累加至本地Double类型变量vRMtratamiento,但在执行vRMtratamiento += object.tratamiento时出现错误:
No exact matches in reference to static method 'buildExpression'
相关代码片段:
@State private var vRMtratamiento: Double = 0.000 (...) VStack{ if !viewModel.listObject_BudgetD.isEmpty { ForEach(1...31, id: \.self) { i in let temp = validarfecha(i: i) if let object = viewModel.listObject_BudgetD.first(where: { $0.id == Int(temp) }) { vRMtratamiento += object.tratamiento } } .onAppear { viewModel.observeListObjectsD() }
已知vRMtratamiento与object.tratamiento均为Double类型,打印object.tratamiento可得到正确数据。
错误原因
SwiftUI的ViewBuilder(比如ForEach的内容闭包)是专门用来构建视图结构的环境,不允许在其中直接执行修改状态的副作用代码。你现在的累加操作属于修改@State变量的行为,违反了ViewBuilder的规则,因此触发了这个编译错误。
解决方案
方法一:将累加逻辑移到视图生命周期方法中
把计算总和的逻辑从ForEach的视图构建闭包中移出,放到onAppear或者数据加载完成的回调里:
VStack{ // 这里只放UI渲染相关代码,比如显示vRMtratamiento的值 Text("总治疗费用:\(vRMtratamiento)") if !viewModel.listObject_BudgetD.isEmpty { ForEach(1...31, id: \.self) { i in let temp = validarfecha(i: i) if let object = viewModel.listObject_BudgetD.first(where: { $0.id == Int(temp) }) { // 这里只做UI渲染,比如显示单日数据 Text("\(i)日:\(object.tratamiento)") } } } } .onAppear { viewModel.observeListObjectsD() // 数据加载完成后计算总和 DispatchQueue.main.async { vRMtratamiento = (1...31).compactMap { i in let temp = validarfecha(i: i) return viewModel.listObject_BudgetD.first(where: { $0.id == Int(temp) })?.tratamiento }.reduce(0, +) } }
方法二:将计算逻辑封装到ViewModel中(推荐)
遵循MVVM架构,把总和计算逻辑放到ViewModel里作为计算属性,这样数据更新时会自动触发视图刷新:
// 在你的ViewModel类中添加计算属性 var totalTratamiento: Double { (1...31).compactMap { i in let temp = validarfecha(i: i) return listObject_BudgetD.first(where: { $0.id == Int(temp) })?.tratamiento }.reduce(0, +) } // 注意:如果validarfecha是View中的方法,需要把它移到ViewModel中,或者改成全局方法
然后在View中直接使用这个计算属性,不需要维护本地的@State变量:
VStack{ Text("总治疗费用:\(viewModel.totalTratamiento)") if !viewModel.listObject_BudgetD.isEmpty { ForEach(1...31, id: \.self) { i in let temp = validarfecha(i: i) if let object = viewModel.listObject_BudgetD.first(where: { $0.id == Int(temp) }) { Text("\(i)日:\(object.tratamiento)") } } } } .onAppear { viewModel.observeListObjectsD() }
注意事项
- 确保
validarfecha返回的内容能正确转换为Int,避免类型转换失败导致数据遗漏 - 如果
listObject_BudgetD是动态更新的(比如实时监听Firebase数据变化),方法二的计算属性会自动同步最新总和,比手动维护@State更可靠
内容的提问来源于stack exchange,提问作者Jeicob1508
相关产品推荐
相关产品推荐

