Swift中Recipe结构体布尔属性持久化失效问题求助
问题:食谱应用中布尔属性无法持久化的解决办法
我正在开发一款基于JSON食谱数据库的应用,能根据用户现有食材返回可用食谱。采用Recipe结构体作为数据模型,用MVVM模式,通过RecipeData这个ObservableObject保存和加载用户的追踪食谱。
相关代码实现
Recipe数据模型
struct Recipe: Codable, Identifiable, Hashable { // 遵循Identifiable协议所需 var id = UUID() var isFavorite: Bool = false var isTracked: Bool = false var isComplete: Bool = false // 核心属性 var title: String // 详细食材(例:1/2 汤匙糖) var ingredients: [String] var directions: [String] var link: String var source: String // 原始食材(例:糖) var NER: [String] // 仅解码JSON文件中包含的属性,其他属性(如id)会被忽略 private enum CodingKeys: String, CodingKey { case title, ingredients, directions, link, source, NER } }
RecipeData数据管理类
class RecipeData: ObservableObject { @Published var recipes = [Recipe]() @Published var usersRecipes = [Recipe]() ... private var documentDirectory: URL { try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) } // 保存和加载用户追踪食谱的代码 private var usersRecipesFile: URL { documentDirectory .appendingPathComponent("usersRecipes") .appendingPathExtension(for: .json) } func saveUsersRecipes() throws { let data = try JSONEncoder().encode(usersRecipes) try data.write(to: usersRecipesFile) } func loadUsersRecipes() throws { guard FileManager.default.isReadableFile(atPath: usersRecipesFile.path) else { return } let data = try Data(contentsOf: usersRecipesFile) usersRecipes = try JSONDecoder().decode([Recipe].self, from: data) } }
MainTabView启动页
struct MainTabView: View { // 用于视图与模型交互的ViewModel @StateObject var recipeData: RecipeData = RecipeData() var body: some View { // 让用户在首页和收藏页之间切换的TabView TabView { HomeScreenView() .tabItem { Label("Home", systemImage: "house") } // 收藏页内容 NavigationView { FavoritesView() .navigationTitle("Favorites") } .tabItem { Label("Favorites", systemImage: "heart.fill") } } .environmentObject(recipeData) // 主TabView显示时加载用户食谱 .onAppear { // try!表示如果出错直接崩溃应用 try! recipeData.loadUsersRecipes() } // 用户食谱变化时自动保存 .onChange(of: recipeData.usersRecipes) { _ in try! recipeData.saveUsersRecipes() } } }
问题描述
将isTracked设为true的Recipe添加到usersRecipes后,当前能在追踪食谱列表正常显示,但关闭重启App后,这些Recipe的isTracked、isComplete、isFavorite均被重置为结构体定义的默认值false,而title、ingredients等其他属性能正常持久化。尝试过将布尔属性改为可选类型,重启后会重置为nil,问题仍未解决。如何让这三个布尔属性正常持久化?
附JSON示例条目:
{ "": 0, "title": "No-Bake Nut Cookies", "ingredients": [ "1 c. firmly packed brown sugar", "1/2 c. evaporated milk", "1/2 tsp. vanilla", "1/2 c. broken nuts (pecans)", "2 Tbsp. butter or margarine", "3 1/2 c. bite size shredded rice biscuits" ], "directions": [ "In a heavy 2-quart saucepan, mix brown sugar, nuts, evaporated milk and butter or margarine.", "Stir over medium heat until mixture bubbles all over top.", "Boil and stir 5 minutes more. Take off heat.", "Stir in vanilla and cereal; mix well.", "Using 2 teaspoons, drop and shape into 30 clusters on wax paper.", "Let stand until firm, about 30 minutes." ], "link": "www.cookbooks.com/Recipe-Details.aspx?id=44874", "source": "Gathered", "NER": [ "brown sugar", "milk", "vanilla", "nuts", "butter", "bite size shredded rice biscuits" ] }
解决方案
问题根源:你的
CodingKeys枚举里没有包含isFavorite、isTracked、isComplete这三个布尔属性,导致JSON编码器在保存时会忽略它们,解码器加载时也不会读取这些字段,自然会使用结构体的默认值。核心修复步骤:
- 更新
Recipe结构体的CodingKeys,把三个布尔属性加入枚举:private enum CodingKeys: String, CodingKey { case title, ingredients, directions, link, source, NER, isFavorite, isTracked, isComplete } - 由于你已经给布尔属性设置了默认值
false,Swift的Codable会自动处理原始JSON中没有这些字段的情况——解码时如果JSON里没有对应字段,就使用默认值,不需要额外编写自定义的init(from decoder:)方法。
- 更新
额外优化建议:
- 代码中的
try!会导致App在出现错误时直接崩溃,建议替换为do-catch块处理错误,避免意外崩溃:.onAppear { do { try recipeData.loadUsersRecipes() } catch { print("加载用户食谱失败:\(error.localizedDescription)") } } .onChange(of: recipeData.usersRecipes) { _ in do { try recipeData.saveUsersRecipes() } catch { print("保存用户食谱失败:\(error.localizedDescription)") } } - 如果希望用户保存的食谱
id在重启后保持一致,可以把id也加入CodingKeys,这样保存和加载时id会被持久化,避免每次重启生成新的UUID。
- 代码中的
内容的提问来源于stack exchange,提问作者Eyan Yehya
相关产品推荐
相关产品推荐

