【问题标题】:typeMismatch Error While parsing JSON data in Swift 4.2在 Swift 4.2 中解析 JSON 数据时出现 typeMismatch 错误
【发布时间】:2019-04-30 16:42:19
【问题描述】:

类型不匹配错误 - 应解码 Array 但找到字典。 我正在使用嵌入在代码中的本地 json 文件。 Json 文件包含有关包的信息。我需要选择值并将它们相应地显示到 tableview 控制器中。请确定我在可编码模型或代码中做错了什么。 JSON 解析未正确处理。

文件格式:

{
  "packages": [
    {
      "name": "Platinum Maksi 6 GB",
      "desc": "Zengin içerikli Platinum Maksi Paketi ile Turkcell Uygulamalarının keyfini sürün!",
      "subscriptionType": "monthly",
      "didUseBefore": true,
      "benefits": [
        "TV+",
        "Fizy",
        "BiP",
        "lifebox",
        "Platinum",
        "Dergilik"
      ],
      "price": 109.90,
      "tariff": {
        "data": "6144",
        "talk": "2000",
        "sms": "100"
      },
      "availableUntil": "1558131150"
    }
]
}

型号: 基础模型

struct Base : Codable {

    let packages : [Package]?

    enum CodingKeys: String, CodingKey {
            case packages = "packages"
    }

    init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            packages = try values.decodeIfPresent([Package].self, forKey: .packages)
    }

2) 封装型号:

struct Package : Codable {

    let availableUntil : String?
    let benefits : String?
    let desc : String?
    let didUseBefore : Bool?
    let name : String?
    let price : Int?
    let subscriptionType : String?
    let tariff : Tariff?

    enum CodingKeys: String, CodingKey {
            case availableUntil = "availableUntil"
            case benefits = "benefits"
            case desc = "desc"
            case didUseBefore = "didUseBefore"
            case name = "name"
            case price = "price"
            case subscriptionType = "subscriptionType"
            case tariff = "tariff"
    }

    init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            availableUntil = try values.decodeIfPresent(String.self, forKey: .availableUntil)
            benefits = try values.decodeIfPresent(String.self, forKey: .benefits)
            desc = try values.decodeIfPresent(String.self, forKey: .desc)
            didUseBefore = try values.decodeIfPresent(Bool.self, forKey: .didUseBefore)
            name = try values.decodeIfPresent(String.self, forKey: .name)
            price = try values.decodeIfPresent(Int.self, forKey: .price)
            subscriptionType = try values.decodeIfPresent(String.self, forKey: .subscriptionType)
            tariff = try Tariff(from: decoder)
    }

}

关税模型:

struct Tariff : Codable {

    let data : String?
    let sms : String?
    let talk : String?

    enum CodingKeys: String, CodingKey {
            case data = "data"
            case sms = "sms"
            case talk = "talk"
    }

    init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            data = try values.decodeIfPresent(String.self, forKey: .data)
            sms = try values.decodeIfPresent(String.self, forKey: .sms)
            talk = try values.decodeIfPresent(String.self, forKey: .talk)
    }

}

我的代码:

var pack = [Package]()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    let url = Bundle.main.url(forResource: "packageList", withExtension: "json")!
    do {
        let data = try Data(contentsOf: url)
        pack = try JSONDecoder().decode([Package].self, from: data)
        print(pack)

    } catch {
        print(error)
    }

【问题讨论】:

    标签: arrays json swift


    【解决方案1】:

    您正在解码错误的对象。您必须始终解码 JSON 的根对象 Base

    使用base.packages 获取Package 数组

    let base = try JSONDecoder().decode(Base.self, from: data)
    pack = base.packages
    

    现在您将收到另外两个类型不匹配错误,将benefits 的类型更改为[String],将price 的类型更改为Double

    您可以显着减少结构:删除所有 CodingKeys 和所有初始化程序并将所有结构成员声明为非可选(删除问号)。

    编辑:

    要将availableUntil 解码为Date,请将其声明为Date

    let availableUntil: Date
    

    并添加自定义日期解码策略,因为该值是一个字符串(如果值为Int会更容易)

    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .custom{ decoder -> Date in
        let container = try decoder.singleValueContainer()
        let dateStr = try container.decode(String.self)
        guard let interval = TimeInterval(dateStr) else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "Date string cannot be converted to TimeInterval") }
        return Date(timeIntervalSince1970: interval)
    }
    let data = try Data(contentsOf: url)
    let base = try decoder.decode(Base.self, from: data)
    pack = base.packages
    

    【讨论】:

    • 谢谢你,关于 let availableUntil : String 我想将它设置为日期。它的值为availableUntil": "1558131150"
    • 非常感谢我真的很感激 :)
    • 如果可能的话,我正在创建 JSON 文件数据 "subscriptionType": "monthly" 的表部分。值是每月、每年和每周。我的代码:enum TableSection: Int { case subscriptionType = 0, yearly, monthly, weekly, total } var data = [TableSection: [[String: String]]]() func sortData() { data[.yearly] = packag.filter({ $0.subscriptionType == "yearly" }) data[.monthly] = packag.filter({ $0.subscriptionType == "monthly" }) data[.weekly] = packag.filter({ $0.subscriptionType == "weekly" }) }
    • 给出错误 - 无法将类型 '[Package]' 的值分配给类型 '[[String : String]]?'
    • 请提出一个新问题(如果有帮助,请接受此问题)。
    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多