类型不匹配错误-预期解码数组但找到字典。 我正在使用代码中嵌入的本地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)
}
答案 0 :(得分:0)
您正在解码错误的对象。您必须始终解码JSON的根对象Base
。
使用Package
获取base.packages
数组
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