如何正确将[Date: String]字典存入UserDefaults?编译报错求助
解决[Date: String]字典存入UserDefaults的问题
你遇到的错误根源是JSON不允许非字符串类型作为字典的键,直接用Date当key会导致JSONEncoder/JSONDecoder处理异常。下面是修正后的实现方案:
核心思路
把Date转换成标准字符串格式(比如ISO8601)作为字典key,存取时在Date和String之间做转换,避开JSON的键类型限制。
修正后的代码
// 扩展Date,实现和ISO字符串的双向转换 extension Date { func toISOString() -> String { ISO8601DateFormatter().string(from: self) } static func fromISOString(_ string: String) -> Date? { ISO8601DateFormatter().date(from: string) } } // 处理字典存取逻辑 guard let transDate = transDate else { // 先处理transDate为nil的情况,避免强制解包崩溃 return } if let transData = UserDefaults.standard.data(forKey: "TransLedger") { print("UPDATE LEDGER") do { // 先解码成[String: String]格式(符合JSON要求) let oldStringDict = try JSONDecoder().decode([String: String].self, from: transData) // 转换成[Date: String]方便业务操作 var oldDict: [Date: String] = [:] for (keyStr, value) in oldStringDict { if let date = Date.fromISOString(keyStr) { oldDict[date] = value } } // 更新字典内容 oldDict[transDate] = productName // 再转换回[String: String]进行编码存储 let newStringDict = oldDict.reduce(into: [String: String]()) { result, pair in result[pair.key.toISOString()] = pair.value } let newData = try JSONEncoder().encode(newStringDict) UserDefaults.standard.set(newData, forKey: "TransLedger") } catch { // 捕获编解码异常,不要用try!避免崩溃 print("数据处理失败: \(error)") } } else { // 首次存储的逻辑 do { let newStringDict = [transDate.toISOString(): productName] let newData = try JSONEncoder().encode(newStringDict) UserDefaults.standard.set(newData, forKey: "TransLedger") } catch { print("首次存储失败: \(error)") } }
关键改进点
- 用
ISO8601DateFormatter实现Date和String的双向转换,保证日期的唯一性和可解析性 - 替换
try!为do-catch捕获异常,避免编解码失败导致崩溃 - 新增可选绑定处理
transDate的nil情况,消除强制解包风险 - 先将字典转换成
[String: String]再进行JSON编解码,完全符合JSON的格式要求
内容的提问来源于stack exchange,提问作者RUSTAM
相关产品推荐
相关产品推荐

