Swift中保存嵌套Map([String: Any])到UserDefaults报错求助
Swift嵌套Map存入UserDefaults失败的解决方法
问题场景
你尝试将包含自定义Races类型的嵌套Map存入UserDefaults,其中userName字段能正常保存,但racesMap字段保存失败,Xcode报错:
Thread 1: "Attempt to insert non-property list object {\n32904 = "app.Races(bestTime: 1, bonusRanking: 0, countryID:0)";\n} for key keyFormapSaving"
错误原因
UserDefaults仅支持存储属性列表类型,包括:String、Int、Double、Bool、Date、Data,以及由这些类型组成的Array或Dictionary。你的racesMap中直接存储了Races实例的字符串描述(或Races对象本身),这两种都不属于合法的属性列表类型,因此触发报错。
解决方案
方案1:通过Codable协议序列化(推荐)
利用Swift的Codable协议将自定义类型转成Data后存储,这是最简洁且可扩展的方式。
- 让
Races结构体遵循Codable协议:
struct Races: Codable { var bestTime: Int var bonusRanking: Int var countryID: Int // 补充你的其他属性 }
- 编码并存储数据:
// 构造原始数据 let racesMap: [Int: Races] = [ 32904: Races(bestTime: 1, bonusRanking: 0, countryID: 0), 32905: Races(bestTime: 1, bonusRanking: 0, countryID: 0) ] do { // 将racesMap编码为Data let racesData = try JSONEncoder().encode(racesMap) // 组装可存储的字典 let saveDict: [String: Any] = [ "racesMap": racesData, "userName": "Alpha" ] // 存入UserDefaults UserDefaults.standard.set(saveDict, forKey: "keyFormapSaving") } catch { print("编码失败:\(error.localizedDescription)") }
- 读取并解码数据:
if let savedDict = UserDefaults.standard.dictionary(forKey: "keyFormapSaving") { // 读取userName let userName = savedDict["userName"] as? String // 读取并解码racesMap if let racesData = savedDict["racesMap"] as? Data { do { let racesMap = try JSONDecoder().decode([Int: Races].self, from: racesData) // 处理恢复后的racesMap } catch { print("解码失败:\(error.localizedDescription)") } } }
方案2:手动转成字典类型
如果不想使用Codable,可以手动将Races实例转成字典,再进行存储。
- 给
Races添加字典转换的扩展:
extension Races { // 转成字典 var toDictionary: [String: Any] { return [ "bestTime": bestTime, "bonusRanking": bonusRanking, "countryID": countryID // 对应其他属性 ] } // 从字典初始化 init?(from dictionary: [String: Any]) { guard let bestTime = dictionary["bestTime"] as? Int, let bonusRanking = dictionary["bonusRanking"] as? Int, let countryID = dictionary["countryID"] as? Int else { return nil } self.bestTime = bestTime self.bonusRanking = bonusRanking self.countryID = countryID // 初始化其他属性 } }
- 存储数据:
let racesMap: [Int: Races] = [ 32904: Races(bestTime: 1, bonusRanking: 0, countryID: 0), 32905: Races(bestTime: 1, bonusRanking: 0, countryID: 0) ] // 将racesMap转成[Int: [String: Any]] let racesDict = racesMap.mapValues { $0.toDictionary } let saveDict: [String: Any] = [ "racesMap": racesDict, "userName": "Alpha" ] UserDefaults.standard.set(saveDict, forKey: "keyFormapSaving")
- 读取数据:
if let savedDict = UserDefaults.standard.dictionary(forKey: "keyFormapSaving") { let userName = savedDict["userName"] as? String if let racesDict = savedDict["racesMap"] as? [Int: [String: Any]] { var racesMap: [Int: Races] = [:] for (key, value) in racesDict { if let race = Races(from: value) { racesMap[key] = race } } // 处理恢复后的racesMap } }
内容的提问来源于stack exchange,提问作者Muhammad Ammar
相关产品推荐
相关产品推荐

