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

SwiftUI中添加食材时@ObservedObject对象未更新问题排查

问题描述

我有两个Section(食材选择区和已添加食材区):食材选择区从JSON文件加载所有食材项,选中食材后应该添加到已添加食材区。目前的问题是:点击添加按钮后,AddedIngredients内部能看到食材被添加,但绑定到已添加区的@ObservedObject var ingredientAdded: AddedIngredients始终显示无数据,导致已添加区没有内容。

我怀疑是不是因为@Published var ingredients = [Ingredient]()属于结构体,每次都会创建新实例?但AddedIngredients是类,理论上应该是引用类型,能共享同一数据才对,我的逻辑哪里错了?


模型代码

import Foundation

struct Ingredient: Codable, Identifiable {
    let id: String
    let price: String
    let ajoute: Bool
}

class AddedIngredients: ObservableObject {
    @Published var ingredients = [Ingredient]()
}

食材选择区代码

struct SectionIngredientsSelection: View {
    let ingredients: [Ingredient]
    @StateObject var ajoute = AddedIngredients()
    var body: some View {
        Section(header: VStack {
            Text("Ajouter vos ingredients")
        }) {
            ForEach(ingredients){ingredient in
                HStack{
                    HStack{
                        Image("mais")
                            .resizable()
                            .frame(width: 20, height: 20)
                        Text(ingredient.id)
                    }
                    Spacer()
                    HStack{
                        Text(ingredient.price )
                        Button(action: {
                            ajoute.ingredients.append(ingredient)
                            print(ajoute.ingredients.count)
                        }){
                            Image(systemName: "plus")
                                .foregroundColor(Color(#colorLiteral(red: 0, green: 0.3257463574, blue: 0, alpha: 1)))
                        }
                    }
                }
            }
            .listRowBackground(Color.white)
            .listRowSeparator(.hidden)
        }
    }
}

已添加食材区代码

struct SectionIngredientsSelected: View {
    @ObservedObject var ingredientAdded :AddedIngredients
    var body: some View {
        Section(header: VStack {
            HStack{
                Text("Vos ingredients")
                    .textCase(nil)
                    .font(.headline)
                    .fontWeight(.bold)
                    .foregroundColor(.black)

                Button(action: {print(ingredientAdded.ingredients.count)}, label: {Text("Add")})
            }
        }) {
            ForEach(ingredientAdded.ingredients){ingredient in
                HStack{
                    HStack{
                        Image("mais")
                            .resizable()
                            .frame(width: 20, height: 20)
                        Text(ingredient.id)
                    }
                    Spacer()
                    HStack{
                        Text(ingredient.price )
                        Button(action: {
                        }){
                            Image(systemName: "xmark.circle")
                                .foregroundColor(Color(#colorLiteral(red: 0, green: 0.3257463574, blue: 0, alpha: 1)))
                        }
                    }
                }
            }
            .listRowBackground(Color.white)
            .listRowSeparator(.hidden)
        }
    }
}

主视图代码

struct CreationView: View {
    let ingredients: [Ingredient] = Bundle.main.decode("Ingredients.json")
    var addedIngre: AddedIngredients
    var body: some View {
        ScrollView {
            VStack{
                VStack(alignment: .leading) {
                    Image("creation")
                        .resizable()
                        .scaledToFit()
                    Text("Slectionnez vos ingredients preferes").fontWeight(.light)
                    Divider()
                        .padding(.bottom)
                }
            }
        }
        List {
            SectionIngredientsSelected(ingredientAdded: addedIngre)
            SectionIngredientsSelection(ingredients: ingredients)
        }
    }
}

解决方案

核心问题是两个子视图使用的是AddedIngredients的不同实例,导致数据无法共享:

  • 主视图的addedIngre传给了SectionIngredientsSelected,但SectionIngredientsSelection自己创建了一个全新的@StateObject var ajoute = AddedIngredients()实例
  • 虽然AddedIngredients是引用类型,但两个视图操作的是不同对象,自然数据不会同步

修改步骤:

  1. 修改食材选择区视图:移除内部的@StateObject实例,改为接收外部传入的AddedIngredients
struct SectionIngredientsSelection: View {
    let ingredients: [Ingredient]
    @ObservedObject var addedIngre: AddedIngredients // 接收外部实例
    var body: some View {
        Section(header: VStack {
            Text("Ajouter vos ingredients")
        }) {
            ForEach(ingredients){ingredient in
                HStack{
                    // 原有UI代码不变
                    HStack{
                        Text(ingredient.price )
                        Button(action: {
                            // 操作共享的实例
                            addedIngre.ingredients.append(ingredient)
                            print(addedIngre.ingredients.count)
                        }){
                            Image(systemName: "plus")
                                .foregroundColor(Color(#colorLiteral(red: 0, green: 0.3257463574, blue: 0, alpha: 1)))
                        }
                    }
                }
            }
            .listRowBackground(Color.white)
            .listRowSeparator(.hidden)
        }
    }
}
  1. 修改主视图:在主视图中创建唯一的AddedIngredients实例,同时传给两个子视图
struct CreationView: View {
    let ingredients: [Ingredient] = Bundle.main.decode("Ingredients.json")
    // 在主视图创建唯一实例,用@StateObject管理生命周期
    @StateObject private var addedIngre = AddedIngredients()
    var body: some View {
        ScrollView {
            // 原有UI代码不变
        }
        List {
            SectionIngredientsSelected(ingredientAdded: addedIngre)
            // 将同一个实例传给食材选择区
            SectionIngredientsSelection(ingredients: ingredients, addedIngre: addedIngre)
        }
    }
}

这样两个子视图就共享同一个AddedIngredients实例了,点击添加按钮后,已添加区会自动更新显示新的食材。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:10:56