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是引用类型,但两个视图操作的是不同对象,自然数据不会同步
修改步骤:
- 修改食材选择区视图:移除内部的
@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) } } }
- 修改主视图:在主视图中创建唯一的
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
相关产品推荐
相关产品推荐

