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
相关产品推荐
相关产品推荐

