如何使用Swift Decodable处理API返回类型不一致的JSON解码问题
解决方案
你可以通过实现可复用的泛型属性包装器来解决该问题,无需手动编写整个结构体的解码逻辑,仅需对需要兼容多类型的字段做标记即可。
首先定义泛型属性包装器:
@propertyWrapper struct FlexibleArray<Element: Decodable>: Decodable { var wrappedValue: [Element] init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() // 优先尝试解码为数组格式 if let arrayResult = try? container.decode([Element].self) { wrappedValue = arrayResult return } // 数组解码失败则尝试解码为单个元素,包装为数组返回 if let singleResult = try? container.decode(Element.self) { wrappedValue = [singleResult] return } // 两种格式都不匹配时抛出解码错误 throw DecodingError.dataCorrupted(DecodingError.Context( codingPath: decoder.codingPath, debugDescription: "Expected type either [\(Element.self)] or \(Element.self)" )) } // 支持默认值初始化(可选) init(wrappedValue: [Element]) { self.wrappedValue = wrappedValue } }
修改你的Movie结构体,仅需对需要兼容的director字段添加属性包装器标记:
struct Movie: Decodable { let title: String let cast: [String] @FlexibleArray var director: [String] }
该方案的优势:
- 侵入性极低,不需要修改原有结构体的其他属性逻辑,也不需要编写全局的解码规则
- 可复用性强,所有需要兼容「单元素/数组」两种返回格式的字段都可以直接加
@FlexibleArray标记使用,支持所有遵守Decodable协议的元素类型 - 外部使用无感知,标记后的属性对外暴露的依然是标准数组类型,不需要额外做类型转换
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

