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

SwiftUI问题:勾选商品时已购数量计算值不更新,仅列表变动时更新

问题原因

你遇到的问题核心在于:GroceryList的@Published var products仅会在数组元素引用发生变化(添加、删除、移动)时触发视图更新,但Product是引用类型(class),修改其acquired属性不会改变数组元素的引用,因此GroceryList不会发布更新,导致顶部的已购商品统计值无法实时刷新。


方案一:将Product改为值类型(推荐,符合SwiftUI设计理念)

把Product从ObservableObject的class改为struct,利用值类型的特性:当acquired属性变化时,数组内的元素会生成新实例,触发GroceryList的products更新,进而让视图重新计算统计值。

修改后的Product代码

struct Product: Identifiable {
    var id = UUID()
    var name: String
    var acquired: Bool
    
    init(name: String, acquired: Bool) {
        self.name = name
        self.acquired = acquired
    }
}

修改ProductRow视图

因为Product现在是值类型,需要用@Binding传递状态:

struct ProductRow: View {
    @Binding var product: Product

    var body: some View {
        HStack {
            Button(action: {
                product.acquired.toggle()
            }, label: {
                Image(systemName: product.acquired ? "checkmark.square" : "square")
            })
            TextField("", text: $product.name)
                .strikethrough(product.acquired)
                .foregroundColor(product.acquired ? .gray : .primary)
        }
    }
}

更新GroceryMainView中的ForEach

直接传递绑定值给ProductRow:

ForEach($grocList.products) { $product in
    if !hideAcquiredProducts || !product.acquired {
        ProductRow(product: $product)
    }
}

方案二:保留Class,手动监听Product的变化

如果必须保留Product作为引用类型,需要让GroceryList监听每个Product的状态变化,当acquired属性改变时手动触发自身更新。

修改后的GroceryList代码

class GroceryList: ObservableObject, Identifiable {
    var id = UUID()
    @Published var date: String
    @Published var products: [Product]
    private var cancellables = Set<AnyCancellable>()
    
    init(date: String, products: [Product]) {
        self.date = date
        self.products = products
        setupProductListeners()
    }
    
    // 监听已有商品的状态变化
    private func setupProductListeners() {
        for product in products {
            trackProductChanges(product)
        }
    }
    
    // 给单个商品添加监听
    private func trackProductChanges(_ product: Product) {
        product.objectWillChange
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
    
    // 添加新商品时同步添加监听
    func addProduct(_ product: Product) {
        trackProductChanges(product)
        products.append(product)
    }
    
    func ProductAcquiredAmount() -> Int {
        products.filter { $0.acquired }.count
    }
}

修改NewProductRow视图

使用新增的addProduct方法添加商品:

struct NewProductRow: View {
    @ObservedObject var groceryList: GroceryList
    @State var newProductName = ""
    
    var body: some View {
        HStack {
            Button(action: {
                guard !newProductName.isEmpty else { return }
                let newProduct = Product(name: newProductName, acquired: false)
                groceryList.addProduct(newProduct)
                newProductName = ""
            }, label: {
                Image(systemName: "plus")
            })
            TextField("...", text: $newProductName)
        }
    }
}

内容的提问来源于stack exchange,提问作者Zef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:30:30