Swift中如何运行时解码类型动态变化的结构体属性
实现方案
完全可以在运行时兼容两种返回格式的正常解码,不需要提前根据请求参数判断返回类型,也不用改接口请求逻辑,只要给League自定义Codable解码逻辑,对standings字段做两种类型的适配即可。
代码实现
你现有的结构体定义不需要大改,只要手动实现init(from:)解码方法,单独处理standings字段的类型兼容即可,其余字段解码逻辑和原来保持一致:
struct League: Codable { let standings: [Standing]? // 保留原有其余属性定义,不需要修改 enum CodingKeys: String, CodingKey { case standings // 补全其余所有属性对应的CodingKey,和原有字段映射一致 } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先尝试按一维数组格式解码 if let singleStandings = try? container.decode([Standing].self, forKey: .standings) { self.standings = singleStandings } // 一维格式解码失败,尝试按二维数组格式解码 else if let groupedStandings = try? container.decode([[Standing]].self, forKey: .standings) { // 按你当前的[Standing]类型定义,直接把二维数组拍平成一维即可 // 如果业务需要保留分组结构,可参考后面的扩展方案调整属性类型 self.standings = groupedStandings.flatMap { $0 } } // 两种格式都不匹配时赋值nil,和原有可选类型逻辑对齐 else { self.standings = nil } // 其余属性按原有逻辑正常解码即可,例: // self.id = try container.decode(Int.self, forKey: .id) // self.leagueName = try container.decode(String.self, forKey: .leagueName) } }
扩展:需要区分两种格式的场景
如果你的业务需要识别返回的是单组排名还是多分组排名(比如多分组要展示分组标题、切换列表样式),可以不用拍平二维数组,定义枚举封装两种类型即可:
enum StandingsResult { case singleGroup([Standing]) case multiGroup([[Standing]]) }
把League中的standings类型替换为StandingsResult?,在解码的两个分支分别给枚举赋值对应关联值即可,后续使用时通过switch判断枚举值就能拿到对应格式的数据。
这套逻辑是运行时自动匹配类型,和你传入的请求参数、列表点击回调逻辑完全解耦,同个endpoint不管返回哪种格式的
standings都能正常解析,不会影响其他字段的解码正确性。
内容的提问来源于stack exchange,提问作者snksnk
相关产品推荐
相关产品推荐

