JSON解码器 - 解码错误w /字符串
在使用可解码协议在Swift 4中创建DotA2 iOS应用程序时,我遇到了这个错误。JSON解码器 - 解码错误w /字符串
keyNotFound(DotaPal.MatchPlayerDetail.CodingKeys.personaname, Swift.DecodingError.Context(codingPath: [DotaPal.MatchDetail.CodingKeys.players, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0))], debugDescription: "No value associated with key personaname (\"personaname\").", underlyingError: nil))
它似乎有解码“personaname”的问题,虽然我不知道为什么。在过去,我已经使用了更复杂的json的解码器,但在看了一段时间后似乎无法找到解决方案:/。
下面是涉及其全部的结构以及json尝试解码的链接。 JSON Attempting to be Decoded
import Foundation
struct MatchDetail {
var match_id: Int?
var barracks_status_dire: Int?
var barracks_status_radiant: Int?
var cluster: Int?
var dire_score: Int?
var duration: Int?
var first_blood_time: Int?
var game_mode: Int?
var radiant_score: Int?
var radiant_win: Int?
var skill: Int?
var start_time: Int?
var tower_status_dire: Int?
var tower_status_radiant: Int?
var players: [MatchPlayerDetail]?
}
extension MatchDetail: Decodable {
enum CodingKeys: String, CodingKey {
case match_id
case barracks_status_dire
case barracks_status_radiant
case cluster
case dire_score
case duration
case first_blood_time
case game_mode
case radiant_score
case radiant_win
case skill
case start_time
case tower_status_dire
case tower_status_radiant
case players
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
match_id = try values.decode(Int?.self, forKey: .match_id)
barracks_status_dire = try values.decode(Int?.self, forKey: .barracks_status_dire)
barracks_status_radiant = try values.decode(Int?.self, forKey: .barracks_status_radiant)
cluster = try values.decode(Int?.self, forKey: .cluster)
dire_score = try values.decode(Int?.self, forKey: .dire_score)
duration = try values.decode(Int?.self, forKey: .duration)
first_blood_time = try values.decode(Int?.self, forKey: .first_blood_time)
game_mode = try values.decode(Int?.self, forKey: .game_mode)
radiant_score = try values.decode(Int?.self, forKey: .radiant_score)
radiant_win = try values.decode(Int?.self, forKey: .radiant_win)
skill = try values.decode(Int?.self, forKey: .skill)
start_time = try values.decode(Int?.self, forKey: .start_time)
tower_status_dire = try values.decode(Int?.self, forKey: .tower_status_dire)
tower_status_radiant = try values.decode(Int?.self, forKey: .tower_status_radiant)
players = try values.decode([MatchPlayerDetail]?.self, forKey: .players)
}
}
struct MatchPlayerDetail {
var match_id: Int?
var player_slot: Int?
var ability_upgrades_arr: [Int?]
var account_id: Int?
var assists: Int?
var backpack_0: Int?
var backpack_1: Int?
var backpack_2: Int?
var deaths: Int?
var denies: Int?
var gold: Int?
var gold_per_min: Int?
var gold_spent: Int?
var hero_damage: Int?
var hero_healing: Int?
var hero_id: Int?
var item_0: Int?
var item_1: Int?
var item_2: Int?
var item_3: Int?
var item_4: Int?
var item_5: Int?
var kills: Int?
var last_hits: Int?
var leaver_status: Int?
var level: Int?
var xp_per_min: Int?
var personaname: String?
var radiant_win: Bool?
var isRadiant: Bool?
var win: Int?
var lose: Int?
var total_gold: Int?
var total_xp: Int?
var kda: Int?
var abandons: Int?
}
extension MatchPlayerDetail: Decodable {
enum CodingKeys: String, CodingKey {
case match_id
case player_slot
case ability_upgrades_arr
case account_id
case assists
case backpack_0
case backpack_1
case backpack_2
case deaths
case denies
case gold
case gold_per_min
case gold_spent
case hero_damage
case hero_healing
case hero_id
case item_0
case item_1
case item_2
case item_3
case item_4
case item_5
case kills
case last_hits
case leaver_status
case level
case xp_per_min
case personaname
case radiant_win
case isRadiant
case win
case lose
case total_gold
case total_xp
case kda
case abandons
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
match_id = try values.decode(Int?.self, forKey: .match_id)
player_slot = try values.decode(Int?.self, forKey: .player_slot)
ability_upgrades_arr = try values.decode([Int?].self, forKey: .ability_upgrades_arr)
assists = try values.decode(Int?.self, forKey: .assists)
backpack_0 = try values.decode(Int?.self, forKey: .backpack_0)
backpack_1 = try values.decode(Int?.self, forKey: .backpack_1)
backpack_2 = try values.decode(Int?.self, forKey: .backpack_2)
deaths = try values.decode(Int?.self, forKey: .deaths)
denies = try values.decode(Int?.self, forKey: .denies)
gold = try values.decode(Int?.self, forKey: .gold)
gold_per_min = try values.decode(Int?.self, forKey: .gold_per_min)
gold_spent = try values.decode(Int?.self, forKey: .gold_spent)
hero_damage = try values.decode(Int?.self, forKey: .hero_damage)
hero_healing = try values.decode(Int?.self, forKey: .hero_healing)
hero_id = try values.decode(Int?.self, forKey: .hero_id)
item_0 = try values.decode(Int?.self, forKey: .item_0)
item_1 = try values.decode(Int?.self, forKey: .item_1)
item_2 = try values.decode(Int?.self, forKey: .item_2)
item_3 = try values.decode(Int?.self, forKey: .item_3)
item_4 = try values.decode(Int?.self, forKey: .item_4)
item_5 = try values.decode(Int?.self, forKey: .item_5)
kills = try values.decode(Int?.self, forKey: .kills)
last_hits = try values.decode(Int?.self, forKey: .last_hits)
leaver_status = try values.decode(Int?.self, forKey: .leaver_status)
level = try values.decode(Int?.self, forKey: .level)
xp_per_min = try values.decode(Int?.self, forKey: .xp_per_min)
personaname = try values.decode(String?.self, forKey: .personaname)
radiant_win = try values.decode(Bool?.self, forKey: .radiant_win)
isRadiant = try values.decode(Bool?.self, forKey: .isRadiant)
win = try values.decode(Int?.self, forKey: .win)
lose = try values.decode(Int?.self, forKey: .lose)
total_gold = try values.decode(Int?.self, forKey: .total_gold)
total_xp = try values.decode(Int?.self, forKey: .total_xp)
kda = try values.decode(Int?.self, forKey: .kda)
abandons = try values.decode(Int?.self, forKey: .abandons)
}
}
那是因为你的第三个球员(指数2)不具有personaname
属性。话虽如此,你有很多不必要的代码。并非所有JSON模型都必须映射到您的代码。如果你不想在Swift模型中使用属性,只需不定义它。
这里有一个较短的版本,其各项属性定义为非可选,除了account_id
和personaname
:
struct MatchDetail: Decodable {
var match_id: Int
var barracks_status_dire: Int
var barracks_status_radiant: Int
var cluster: Int
var dire_score: Int
var duration: Int
var first_blood_time: Int
var game_mode: Int
var radiant_score: Int
var radiant_win: Int
var skill: Int
var start_time: Int
var tower_status_dire: Int
var tower_status_radiant: Int
var players: [MatchPlayerDetail]
}
struct MatchPlayerDetail: Decodable {
var match_id: Int
var player_slot: Int
var ability_upgrades_arr: [Int]
var account_id: Int?
var assists: Int
var backpack_0: Int
var backpack_1: Int
var backpack_2: Int
var deaths: Int
var denies: Int
var gold: Int
var gold_per_min: Int
var gold_spent: Int
var hero_damage: Int
var hero_healing: Int
var hero_id: Int
var item_0: Int
var item_1: Int
var item_2: Int
var item_3: Int
var item_4: Int
var item_5: Int
var kills: Int
var last_hits: Int
var leaver_status: Int
var level: Int
var xp_per_min: Int
var personaname: String?
var radiant_win: Bool
var isRadiant: Bool
var win: Int
var lose: Int
var total_gold: Int
var total_xp: Int
var kda: Int
var abandons: Int
}
你的时间上经历的资料应有看看哪些关键更好地用是可选的,哪一个是不。 Swift可以为你合成JSON解码。
OMG,这么多问号。为什么你要编写自定义初始值设定项,虽然你正在解码的值1:1(除非我失去了一些东西)? – vadian
PS:什么是解码为可选类型,如“Int?.self”? WWDC视频没有提及/表明这一点。 – vadian
感谢您的评论,我将重新阅读解码器。自定义init是否存在,因为json完全不匹配结构。 – Rykuno