如何基于Codable协议解码JSON响应中的嵌套数据?
嵌套JSON的Codable优化解码方案
针对API返回的外层对象包含posts数组的JSON结构,无需手动通过JSONSerialization转Data,也不用额外定义冗余的外层Response模型,以下是几种更简洁的Codable实现方案:
方案一:直接解码外层字典取目标数组
利用JSONDecoder直接解码外层字典,取出对应键的数组,代码简洁直观:
do { let responseDict = try JSONDecoder().decode([String: [Post]].self, from: data) guard let decodedPosts = responseDict["posts"] else { completion(.failure(.decodeError)) return } completion(.success(decodedPosts)) } catch { completion(.failure(.decodeError)) }
方案二:扩展JSONDecoder实现通用嵌套解码
如果需要多次处理类似的嵌套结构,给JSONDecoder添加扩展,支持指定嵌套键直接解码目标类型,复用性强:
extension JSONDecoder { func decode<T: Decodable>(_ type: T.Type, from data: Data, nestedKey key: String) throws -> T { let keyedContainer = try decode([String: T].self, from: data) guard let targetValue = keyedContainer[key] else { throw DecodingError.keyNotFound( CodingKey(stringValue: key, intValue: nil), DecodingError.Context( codingPath: [], debugDescription: "嵌套键\(key)未在响应中找到" ) ) } return targetValue } }
使用时只需一行代码完成解码:
do { let decodedPosts = try JSONDecoder().decode([Post].self, from: data, nestedKey: "posts") completion(.success(decodedPosts)) } catch { completion(.failure(.decodeError)) }
方案三:通用嵌套解码Wrapper
定义一个通用的NestedDecoder结构体,专门处理从指定嵌套键解码目标类型的场景,适合需要统一处理多种嵌套结构的项目:
struct NestedDecoder<T: Decodable>: Decodable { let value: T init(from decoder: Decoder) throws { let rootContainer = try decoder.container(keyedBy: CodingKeys.self) value = try rootContainer.decode(T.self, forKey: .posts) } enum CodingKeys: String, CodingKey { case posts } }
使用时通过Wrapper间接获取目标数组:
do { let resultWrapper = try JSONDecoder().decode(NestedDecoder<[Post]>.self, from: data) completion(.success(resultWrapper.value)) } catch { completion(.failure(.decodeError)) }
如果需要支持其他嵌套键,可修改CodingKeys或给NestedDecoder添加带键初始化的版本。
以上方案均基于Codable协议实现,全程保持类型安全,避免了手动解析的繁琐操作。
内容的提问来源于stack exchange,提问作者Shawn Frank
相关产品推荐
相关产品推荐

