如何将JSON解码为不同类型?Swift自定义Decodable初始化报错排查
问题根源
两个核心错误直接导致报错与解码失败:
- 容器类型选择错误:JSON单条记录为带key的对象结构,需使用
keyedContainer(keyedBy:)读取对应字段,你所使用的singleValueContainer()仅适用于无结构的单值内容解析,完全不匹配当前JSON结构。 - 初始化逻辑不完整:你编写的switch分支每次仅对3个属性中的1个赋值,剩余2个存储属性始终未完成初始化,触发了Swift编译器的存储属性初始化完整性检查,直接抛出编译错误。同时你先尝试将整个容器解码为String的逻辑,和实际JSON结构完全不符,即使编译通过运行时也会解码失败。
正确实现方案
由于JSON中的日期为自定义字符串格式,需要先配置对应格式的日期解析器,推荐以下两种实现方式:
方案1:依赖自动合成解码逻辑(无需手写init,代码量最少)
import Foundation struct Event: Decodable & Equatable { let title: String let start: Date let end: Date } // 解码流程示例 let jsonData = 你的JSON数据变量 // 配置对应格式的日期解析器 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MMMM dd, yyyy h:mm a" dateFormatter.locale = Locale(identifier: "en_US_POSIX") // 避免系统区域设置影响解析 let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(dateFormatter) do { let events = try decoder.decode([Event].self, from: jsonData) // 解析完成后可直接使用events数组 } catch { print("解码失败: \(error)") }
方案2:手写自定义init(from:)实现
如果有自定义解码的业务需求,正确的解码init写法如下:
struct Event: Decodable & Equatable { let title: String let start: Date let end: Date enum CodingKeys: String, CodingKey { case title, start, end } init(from decoder: Decoder) throws { // 使用keyed容器读取所有字段 let container = try decoder.container(keyedBy: CodingKeys.self) // 依次完成三个属性的解码赋值,全部赋值完成后再结束初始化流程 self.title = try container.decode(String.self, forKey: .title) self.start = try container.decode(Date.self, forKey: .start) self.end = try container.decode(Date.self, forKey: .end) } } // 解码时的日期配置和方案1完全一致
内容的提问来源于stack exchange,提问作者Fernando Ivan Perez Ruiz
相关产品推荐
相关产品推荐

