You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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后存储,这是最简洁且可扩展的方式。

  1. 让Races结构体遵循Codable协议:
struct Races: Codable {
    var bestTime: Int
    var bonusRanking: Int
    var countryID: Int
    // 补充你的其他属性
}
  1. 编码并存储数据:
// 构造原始数据
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)")
}
  1. 读取并解码数据:
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实例转成字典,再进行存储。

  1. 给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
        // 初始化其他属性
    }
}
  1. 存储数据:
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")
  1. 读取数据:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:36:01