SwiftUI将数据存入UserDefaults后列表视图读取为nil如何解决
问题排查及修复方案
1. 首先确认Meal模型已遵守Codable协议
你当前使用JSONEncoder/JSONDecoder处理序列化,要求Meal以及它所有属性的类型都必须实现Codable协议,漏写的话会导致编码直接失败,try?会返回nil,数据根本不会写入UserDefaults,读取自然为空。
示例正确的模型声明:
struct Meal: Identifiable, Codable { // 必须声明遵守Codable协议 let id = UUID() let name: String let imageUrlString: String let ingredients: [String] let instructions: String let area: String let category: String }
如果你的模型里包含自定义类型,该自定义类型也需要同步遵守Codable协议,否则也会导致编码失败。
2. 确认全局使用同一个SavedMeals实例
如果在不同页面各自初始化SavedMeals(),会导致你在ContentView里修改的实例和SavedMealsView接收的不是同一个对象,读取自然是空。
正确的做法是在App入口处初始化一次,通过@EnvironmentObject全局传递:
@main struct YourApp: App { @StateObject private var savedMeals = SavedMeals() var body: some Scene { WindowGroup { ContentView() .environmentObject(savedMeals) } } }
然后在所有用到的页面通过环境变量读取,不要单独初始化:
// ContentView和SavedMealsView里统一这么声明 @EnvironmentObject var savedMeals: SavedMeals
3. 移除强制解包避免逻辑中断
你代码里的self.mealGenerator.currentMeal!强制解包如果遇到currentMeal为nil的情况会直接崩溃,不会走到后续的存数据逻辑,建议改成可选绑定判断:
Button("Save Meal") { guard let currentMeal = self.mealGenerator.currentMeal else { return } let meal = Meal(name: currentMeal.name, imageUrlString: currentMeal.imageUrlString, ingredients: currentMeal.ingredients, instructions: currentMeal.instructions, area: currentMeal.area, category: currentMeal.category) self.savedMeals.meals.append(meal) self.savedMeals.saveMeals() }
4. 调试定位具体失败节点
可以加打印快速定位是存失败还是读失败:
// 在saveMeals里添加错误打印 func saveMeals() { do { let encoded = try JSONEncoder().encode(meals) UserDefaults.standard.set(encoded, forKey: "Meals") print("保存成功,数据长度:\(encoded.count)") } catch { print("编码失败:\(error)") // 这里会输出具体的编码错误原因 } } // 在init里添加错误打印 init() { if let mealsData = UserDefaults.standard.data(forKey: "Meals") { print("读取到存储数据,长度:\(mealsData.count)") do { let decoded = try JSONDecoder().decode([Meal].self, from: mealsData) self.meals = decoded print("解码成功,共\(decoded.count)条数据") return } catch { print("解码失败:\(error)") // 输出具体的解码错误原因 } } self.meals = [] }
内容的提问来源于stack exchange,提问作者MjDev
相关产品推荐
相关产品推荐

