如何基于Codable协议按类型解码JSON至对应Collection对象
解决Codable根据collectionType动态解析data字段的问题
这是个很常见的动态类型解码场景,我来一步步帮你实现根据collectionType的值,把data字段解析成对应的[Item]或[Location]数组:
1. 用枚举封装不同的data类型
首先给Collection类添加一个枚举类型CollectionData,用来承载两种不同的data数组类型,既保证类型安全,又避免使用Any带来的类型歧义:
enum CollectionData: Codable { case items([Item]) case locations([Location]) }
2. 修改Collection类并实现自定义解码
接下来调整你的Collection类,把data字段类型改为CollectionData,然后手动实现init(from decoder:)方法——在这个方法里我们先解析collectionType,再根据它的值去解码对应的data类型:
class Collection: NSObject, Codable { // MARK: - Properties let collectionType: String let collectionName: String let data: CollectionData // MARK: - CodingKeys private enum CodingKeys: String, CodingKey { case collectionType, collectionName, data // 别忘了加上data字段 } // 自定义解码逻辑 required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解析固定字段 self.collectionType = try container.decode(String.self, forKey: .collectionType) self.collectionName = try container.decode(String.self, forKey: .collectionName) // 根据collectionType解析对应的data switch self.collectionType { case "item": let items = try container.decode([Item].self, forKey: .data) self.data = .items(items) case "location": let locations = try container.decode([Location].self, forKey: .data) self.data = .locations(locations) default: // 处理未知的collectionType,抛出明确的解码错误 throw DecodingError.dataCorruptedError( forKey: .collectionType, in: container, debugDescription: "Unsupported collection type: \(self.collectionType)" ) } } }
你的Item和Location类不需要修改,保持原实现即可:
class Item: NSObject, Codable { // MARK: - Properties let itemTitle: String let itemSubtitle: String // MARK: - CodingKeys private enum CodingKeys: String, CodingKey { case itemTitle, itemSubtitle } } class Location: NSObject, Codable { // MARK: - Properties let locationName: String // MARK: - CodingKeys private enum CodingKeys: String, CodingKey { case locationName } }
3. 使用解析后的对象
当你把JSON解码成[Collection]数组后,可以通过switch语句轻松处理不同类型的data:
// 假设jsonData是你的JSON数据 do { let collections = try JSONDecoder().decode([Collection].self, from: jsonData) for collection in collections { print("Collection name: \(collection.collectionName)") switch collection.data { case .items(let items): print("This is an item collection, count: \(items.count)") // 遍历处理Item对象 for item in items { print("- Item: \(item.itemTitle) / \(item.itemSubtitle)") } case .locations(let locations): print("This is a location collection, count: \(locations.count)") // 遍历处理Location对象 for location in locations { print("- Location: \(location.locationName)") } } } } catch { print("Decoding error: \(error)") }
为什么要这么做?
默认的Codable解码是静态的,无法根据其他字段的值动态调整解码类型。通过手动实现init(from decoder:),我们可以先获取collectionType的取值,再针对性地解码data字段,完美匹配你的JSON结构需求。
内容的提问来源于stack exchange,提问作者Luda
相关产品推荐
相关产品推荐

