SwiftUI+SwiftData重复添加删除食谱崩溃问题求助
问题分析
报错核心是SwiftData期望ingredients属性为NSData类型,但实际传入的是Swift数组。这是因为SwiftData默认会将非模型对象的数组尝试归档为二进制数据,但你的Ingredient要么是未正确支持归档的结构体,要么改成@Model类后关联配置错误。
解决方案
1. 将Ingredient定义为@Model类,建立与Recipe的关联
把原本的Ingredient结构体改成@Model类,同时在Recipe的ingredients属性上添加@Relationship,明确父子关系和删除规则:
@Model class Ingredient { var text: String var food: String var foodId: String init(text: String, food: String, foodId: String) { self.text = text self.food = food self.foodId = foodId } } @Model class Recipe { var title: String var imageUrl: String @Relationship(deleteRule: .cascade) // 删除Recipe时自动删除关联的Ingredient var ingredients: [Ingredient] var url: String var totalTime: Double init(title: String, imageUrl: String, ingredients: [Ingredient], url: String, totalTime: Double) { self.title = title self.imageUrl = imageUrl self.ingredients = ingredients self.url = url self.totalTime = totalTime } }
2. 修正API数据到模型的转换逻辑
API返回的是结构体类型的Ingredient,需要转换成@Model标记的Ingredient类实例,再传入Recipe初始化:
// 重命名API解码用的结构体,避免和模型类冲突 struct ApiIngredient: Decodable { var text: String var food: String var foodId: String } struct ApiResponse: Decodable { var count: Int var hits: [RecipeObject] struct RecipeObject: Decodable { var recipe: RecipeModel struct RecipeModel: Decodable { var label: String var image: String var ingredients: [ApiIngredient] // 使用重命名后的结构体 var url: String var totalTime: Double } } } extension Recipe { convenience init(from recipe: ApiResponse.RecipeObject.RecipeModel) { // 将API结构体转换成模型类实例 let ingredientModels = recipe.ingredients.map { apiIngredient in Ingredient(text: apiIngredient.text, food: apiIngredient.food, foodId: apiIngredient.foodId) } self.init( title: recipe.label, imageUrl: recipe.image, ingredients: ingredientModels, url: recipe.url, totalTime: recipe.totalTime ) } }
3. 确保上下文操作正确,手动保存状态
在添加/删除收藏的方法中,操作后手动保存上下文,避免状态不一致:
func addRecipeToFavorite(modelContext: ModelContext, recipe: Recipe) { modelContext.insert(recipe) do { try modelContext.save() } catch { print("保存收藏失败: \(error.localizedDescription)") } } func removeRecipeFromFavorite(modelContext: ModelContext, recipe: Recipe) { modelContext.delete(recipe) do { try modelContext.save() } catch { print("删除收藏保存失败: \(error.localizedDescription)") } }
4. 删除后再次添加的注意事项
删除Recipe后,原实例已被标记为删除状态,不能再次插入。再次添加时,必须基于API数据创建新的Recipe实例,不能复用之前被删除的对象。
关键说明
- SwiftData中,关联的模型必须都是
@Model标记的类,不能混合结构体和模型类数组 @Relationship的deleteRule: .cascade确保删除Recipe时,关联的Ingredient会被自动删除,避免数据残留- 手动保存上下文可以确保操作立即持久化,避免上下文状态混乱导致崩溃
内容的提问来源于stack exchange,提问作者simsab
相关产品推荐
相关产品推荐

