You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:00:18