Swift解码含多类型字典数组的JSON遇阻,求模型修改方案
解决Swift中JSON多类型字典的Codable解码问题
问题核心
当前代码将alerts定义为[[String:String]],但目标JSON中包含多种值类型:时间戳(Int)、坐标数组([[Double]])、嵌套对象数组(affectedZoneIDs)等,导致类型不匹配解码失败。同时现有模型结构混乱(CodingKeys位置错误、模型间无正确关联),无法正确映射JSON结构。
解决方案步骤
1. 重构顶层模型
将顶层模型的alerts类型从字典数组改为具体的模型数组,每个alert对应固定结构的结构体:
struct AlertsResponse: Decodable { let alerts: [Alert] }
2. 定义完整的Alert结构体
根据JSON字段逐一映射,使用对应的数据类型:
- 时间戳字段用
TimeInterval接收(或直接用Date,配合解码器配置) - 嵌套对象数组
affectedZoneIDs定义为自定义结构体数组 - 坐标数组
polygon、multiPolygon用多维Double数组对应
struct Alert: Decodable { let id: String let areaDescription: String let dateSent: Date let dateEffective: Date let dateOnset: Date let dateExpires: Date let dateEnds: Date let severity: String let certainty: String let urgency: String let senderName: String let description: String let instruction: String? // 标记为可选,避免JSON缺失字段时解码失败 let response: String let event: String let headline: String let nwsHeadline: [String] let polygon: [[Double]] let multiPolygon: [[[Double]]] let affectedZoneIDs: [AffectedZone] let messageType: String } struct AffectedZone: Decodable { let type: String let id: String }
3. 配置JSONDecoder处理日期
JSON中的时间是秒级时间戳,设置解码器策略直接转为Date:
let decoder = JSONDecoder() decoder.dateDecodingStrategy = .secondsSince1970
4. 适配业务模型WeatherAlertsModel
如果需要将Alert映射到业务模型,添加初始化方法完成字段转换:
struct WeatherAlertsModel { var alertTitle: String var startDateAlert: Date var endDateAlert: Date var sourceOfAlert: String var severity: String var certainty: String var urgency: String var description: String var affectedZoneIDs: [String] init(from alert: Alert) { self.alertTitle = alert.event self.startDateAlert = alert.dateOnset self.endDateAlert = alert.dateEnds self.sourceOfAlert = alert.senderName self.severity = alert.severity self.certainty = alert.certainty self.urgency = alert.urgency self.description = alert.description self.affectedZoneIDs = alert.affectedZoneIDs.map { $0.id } } }
5. 修改发布者代码
调整解码类型,并按需映射到业务模型:
func getWeatherAlerts() -> AnyPublisher<[WeatherAlertsModel], Error> { guard let url = URL(string: "https://api.alltheapps.org/weather/v3/allActiveAlerts?apiKey=da230328") else { return Fail(error: CustomError.invalidUrl).eraseToAnyPublisher() } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .secondsSince1970 return URLSession.shared.dataTaskPublisher(for: url) .map(\.data) .decode(type: AlertsResponse.self, decoder: decoder) .map { response in response.alerts.map(WeatherAlertsModel.init) } .eraseToAnyPublisher() }
关键说明
- 避免使用
Any或[String:Any]类型,Codable对具体类型的支持更稳定可靠 - 可选字段添加
?标记,防止JSON中缺失该字段导致解码失败 - 多维数组类型需与JSON结构严格对应(如
multiPolygon是三维数组[[[Double]]])
内容的提问来源于stack exchange,提问作者Daniel Ardeleanu
相关产品推荐
相关产品推荐

