JSON解码器 - 解码错误w /字符串

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) 
    } 
} 
+1

OMG,这么多问号。为什么你要编写自定义初始值设定项,虽然你正在解码的值1:1(除非我失去了一些东西)? – vadian

+0

PS:什么是解码为可选类型,如“Int?.self”? WWDC视频没有提及/表明这一点。 – vadian

+0

感谢您的评论,我将重新阅读解码器。自定义init是否存在,因为json完全不匹配结构。 – Rykuno

那是因为你的第三个球员(指数2)不具有personaname属性。话虽如此,你有很多不必要的代码。并非所有JSON模型都必须映射到您的代码。如果你不想在Swift模型中使用属性,只需不定义它。

这里有一个较短的版本,其各项属性定义为非可选,除了account_idpersonaname

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解码。