Swift 4中如何用Codable替代ObjectMapper解析嵌套JSON
用Codable实现无嵌套结构体的点语法访问
嘿,我懂你想要的——不用为JSON里的每一层嵌套都定义专属结构体,像用ObjectMapper那样灵活地通过点语法访问属性对吧?刚好Swift的**动态成员查找(Dynamic Member Lookup)**特性可以帮我们实现这个需求,配合Codable就能摆脱繁琐的结构体定义!
方案:通用JSON容器 + 动态成员查找
我们可以定义一个带@dynamicMemberLookup修饰的通用Codable结构体,它能自动处理任意嵌套的JSON结构,让你直接用点语法访问属性:
@dynamicMemberLookup struct JSONContainer: Codable { private let container: KeyedDecodingContainer<CodingKeys> // 自定义CodingKey,支持任意字符串键 private struct CodingKeys: CodingKey { var stringValue: String init?(stringValue: String) { self.stringValue = stringValue } var intValue: Int? init?(intValue: Int) { return nil } } // 解码初始化方法 init(from decoder: Decoder) throws { self.container = try decoder.container(keyedBy: CodingKeys.self) } // 编码方法(如果不需要编码可以省略) func encode(to encoder: Encoder) throws { var targetContainer = encoder.container(keyedBy: CodingKeys.self) for key in container.allKeys { try targetContainer.encode(container.decode(JSONContainer.self, forKey: key), forKey: key) } } // 动态成员查找的核心:通过属性名动态解码 subscript<T: Codable>(dynamicMember member: String) -> T? { get { guard let key = CodingKeys(stringValue: member) else { return nil } return try? container.decode(T.self, forKey: key) } } }
如何使用这个容器
用它解析你提供的JSON字符串,直接通过点语法访问任意嵌套属性,完全不用定义Health、Size这类结构体:
let jsonString = """ { "health": { "size":{ "width":150, "height":150 }, "name":"Apple" } } """ do { let rootContainer = try JSONDecoder().decode(JSONContainer.self, from: jsonString.data(using: .utf8)!) // 直接用点语法访问嵌套属性,指定类型即可 let healthName: String? = rootContainer.health.name let sizeWidth: Double? = rootContainer.health.size.width let sizeHeight: Double? = rootContainer.health.size.height print("Name: \(healthName ?? "Unknown")") // Name: Apple print("Size: \(sizeWidth ?? 0)x\(sizeHeight ?? 0)") // Size: 150.0x150.0 } catch { print("解码失败:\(error.localizedDescription)") }
注意事项
- 访问时需要明确指定类型(比如
String?、Double?),因为Swift需要知道你要解码成什么类型; - 如果JSON里的类型和你指定的不匹配(比如你原来ObjectMapper里把
name定义成Double?但JSON里是字符串),解码会返回nil,所以要确保类型对应; - 这个容器支持无限嵌套,不管JSON有多深,都能通过点语法一层层访问。
这样就完美替代了ObjectMapper的写法,又不用写一堆重复的结构体,是不是很方便?
内容的提问来源于stack exchange,提问作者salman siddiqui
相关产品推荐
相关产品推荐

