You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:54:59