Swift JSON解码器类型不匹配错误

Posted

技术标签:

【中文标题】Swift JSON解码器类型不匹配错误【英文标题】:Swift JSONDecoder typeMismatch error 【发布时间】:2017-12-29 13:06:00 【问题描述】:

我正在尝试使用 JSONDecoder 将 JSON 转换为 Swift 中的结构,所以我编写了所有结构,修改了几个小时,它仍然给我这个错误。我不知道是否有办法看到给出这个的线。 我将在下面发布我的结构和 Json 文件链接。

完整的错误描述是:

typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [], debugDescription: “应解码 Dictionary 但找到一个数组 而是。”,基础错误:无))

//  Created by Breno Ramos on 28/12/17.
//  Copyright © 2017 brenor2. All rights reserved.
//

import Foundation

struct Owner:Decodable 
    let login               : String?
    let id                  : Double?
    let avatar_url          : String?
    let gravatar_id         : String?
    let url                 : String?
    let html_url            : String?
    let followers_url       : String?
    let following_url       : String?
    let gists_url           : String?
    let starred_url         : String?
    let subscriptions_url   : String?
    let organizations_url   : String?
    let repos_url           : String?
    let events_url          : String?
    let received_events_url : String?
    let type                : String?
    let site_admin          : Bool?


struct License:Decodable 
    let key     : String?
    let name    : String?
    let spdx_id : String?
    let url     : String?


struct Repo:Decodable 
    let id                : Double?
    let name              : String?
    let full_name         : String?
    let owner             : Owner?
    let `private`         : Bool?
    let html_url          : String?
    let description       : String?
    let fork              : Bool?
    let url               : String?
    let forks_url         : String?
    let keys_url          : String?
    let collaborators_url : String?
    let teams_url         : String?
    let hooks_url         : String?
    let issue_events_url  : String?
    let events_url        : String?
    let assignees_url     : String?
    let branches_url      : String?
    let tags_url          : String?
    let blobs_url         : String?
    let git_tags_url      : String?
    let git_refs_url      : String?
    let trees_url         : String?
    let statuses_url      : String?
    let languages_url     : String?
    let stargazers_url    : String?
    let contributors_url  : String?
    let subscribers_url   : String?
    let subscription_url  : String?
    let commits_url       : String?
    let git_commits_url   : String?
    let comments_url      : String?
    let issue_comment_url : String?
    let contents_url      : String?
    let compare_url       : String?
    let merges_url        : String?
    let archive_url       : String?
    let downloads_url     : String?
    let issues_url        : String?
    let pulls_url         : String?
    let milestones_url    : String?
    let notifications_url : String?
    let labels_url        : String?
    let releases_url      : String?
    let deployments_url   : String?
    let created_at        : String?
    let updated_at        : String?
    let pushed_at         : String?
    let git_url           : String?
    let ssh_url           : String?
    let clone_url         : String?
    let svn_url           : String?
    let homepage          : String?
    let size              : Double?
    let stargazers_count  : Double?
    let watchers_count    : Double?
    let language          : String?
    let has_issues        : Bool?
    let has_projects      : Bool?
    let has_downloads     : Bool?
    let has_wiki          : Bool?
    let has_pages         : Bool?
    let forks_count       : Double?
    let mirror_url        : String?
    let archived          : Bool?
    let open_issues_count : Double?
    let license           : License?
    let forks             : Double?
    let open_issues       : Double?
    let topics            : Topic?
    let permissions       : Permissions?
    let watchers          : Double?
    let default_branch    : String?
    //    let score             : Double?
    //    let subscribers_count : Double?
    //    let network_count     : Double?
    //    let allow_rebase_merge: Bool?
    //    let allow_squash_merge: Bool?
    //    let allow_merge_commit: Bool?



struct Topic:Decodable 
    let topics : [String]?


struct Permissions:Decodable 
    let admin : Bool
    let push  : Bool
    let pull  : Bool


struct RepoList:Decodable
    let total_count        : Int?
    let incomplete_results : Bool?
    let items              : [Repo]?


struct User:Decodable 
    let login: String?
    let id: Double?
    let avatar_url: String?
    let gravatar_id: String?
    let url: String?
    let html_url: String?
    let followers_url: String?
    let following_url: String?
    let gists_url: String?
    let starred_url: String?
    let subscriptions_url: String?
    let organizations_url: String?
    let repos_url: String?
    let events_url: String?
    let received_events_url: String?
    let type: String?
    let site_admin: Bool?


struct Creator:Decodable 
    let login: String?
    let id: Double?
    let avatar_url: String?
    let gravatar_id: String?
    let url: String?
    let html_url: String?
    let followers_url: String?
    let following_url: String?
    let gists_url: String?
    let starred_url: String?
    let subscriptions_url: String?
    let organizations_url: String?
    let repos_url: String?
    let events_url: String?
    let received_events_url: String?
    let type: String?
    let site_admin: Bool?


struct Link:Decodable 
    let href :String?


struct _Links:Decodable 
    let `self`           :Link?
    let html             :Link?
    let issue            :Link?
    let comments         :Link?
    let review_comments  :Link?
    let review_comment   :Link?
    let commits          :Link?
    let statuses         :Link?


struct Base:Decodable 
    let label :String?
    let ref   :String?
    let sha   :String?
    let user  :User?
    let repo  :Repo?


struct Head:Decodable 
    let label :String?
    let ref   :String?
    let sha   :String?
    let user  :User?
    let repo  :Repo?


struct Milestone:Decodable 
    let url:String?
    let html_url:String?
    let labels_url:String?
    let id: Double?
    let number:Double?
    let title:String?
    let description:String?
    let creator:Creator?
    let open_issues:Double?
    let closed_issues:Double?
    let state:String?
    let created_at:String?
    let updated_at:String?
    let closed_at:String?
    let due_on:String?


struct Assignee:Decodable 
    let login               :String?
    let id                  :Double?
    let avatar_url          :String?
    let gravatar_id         :String?
    let url                 :String?
    let html_url            :String?
    let followers_url       :String?
    let following_url       :String?
    let gists_url           :String?
    let starred_url         :String?
    let subscriptions_url   :String?
    let organizations_url   :String?
    let repos_url           :String?
    let events_url          :String?
    let received_events_url :String?
    let type                :String?
    let site_admin          :Bool?


struct Reviewers:Decodable 
    let login: String?
    let id: Double?
    let avatar_url: String?
    let gravatar_id: String?
    let url: String?
    let html_url: String?
    let followers_url: String?
    let following_url: String?
    let gists_url: String?
    let starred_url: String?
    let subscriptions_url: String?
    let organizations_url: String?
    let repos_url: String?
    let events_url: String?
    let received_events_url: String?
    let type: String?
    let site_admin: Bool?


struct Pull:Decodable 
    let id: Double?
    let url:String?
    let html_url:String?
    let diff_url:String?
    let patch_url:String?
    let issue_url:String?
    let number:Double?
    let state:String?
    let locked:Bool?
    let title:String?
    let user:User?
    let body:String?
    let created_at:String?
    let updated_at:String?
    let closed_at:String?
    let merged_at:String?
    let merge_commit_sha: String?
    let assignee: Assignee?
    let assignees: [Assignee]?
    let requested_reviewers: [Reviewers]?
    let milestone:Milestone?
    let commits_url:String?
    let review_comments_url:String?
    let review_comment_url:String?
    let comments_url:String?
    let statuses_url:String?
    let head:Head?
    let base:Base?
    let _links:_Links?
    let author_association:String?


struct PullList:Decodable 
    let pulls:[Pull]?





/////////////////////////////////////////////////////////

1.This one is working fine with this structs: 2.This one is the one that gives the typeMismatch error

【问题讨论】:

不工作的是Array 第一个 JSON 有一个字典作为***对象,第二个 JSON 有一个数组——正如错误消息清楚地表明的那样。 【参考方案1】:

你现在可能正在这样做:

let decoder = JSONDecoder()
let repoList = decoder.decode(RepoList.self, from: data)

这对于***对象的响应很好。

要解码***数组的 JSON 响应,请改用如下代码:

let decoder = JSONDecoder()
let repos = decoder.decode([Repo].self, from: data)

【讨论】:

我遇到了同样的问题。我从 api 询问单个 json 对象,但即使对于单个 json 对象,api 的结果也总是带有数组。这就是为什么你需要像第二个那样修复你的代码,然后拿第一个并返回它。【参考方案2】:

如果您有一个有问题的JSON,它可能包含一些键的数字或字符串,您可以解码没有该属性的对象并在解码后手动设置该属性。

例如,我在HistoryItem 中有一个Vehicle 类。在Vehicle model_year 可以为空String 或非空Int。在这里,我正在使用NSDictionary 手动解码modelYear 并尝试获取IntSwift 4 无法自动完成。

do 
    // Decoding HistoryItem from JSON
    let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
    let decoder = JSONDecoder()
    let historyItem = try decoder.decode(HistoryItem.self, from: jsonData)
    if let modelYear = (dict as NSDictionary).value(forKeyPath: "vehicle.model_year") as? Int 
        historyItem.vehicle?.modelYear = modelYear
    

    // Saving HistoryItem to Realm
    let realm = try! Realm()
    try! realm.write 
        realm.add(historyItem, update: true)
    

 catch 
    print(error.localizedDescription)

这是我的Vehicle 类,包含在HistoryItem 中:

class Vehicle: Object, Codable 
    @objc dynamic var VIN: String = ""
    @objc dynamic var make: String?
    @objc dynamic var modelName: String?
    @objc dynamic var recallCount: Int = 0
    @objc dynamic var modelYear: Int = 0

    override static func primaryKey() -> String? 
        return "VIN"
    

    private enum CodingKeys: String, CodingKey 
        case VIN = "vin"
        case make
        case modelName = "model_name"
        case recallCount = "recall_count"
    

如您所见,CodingKeys 中没有 model_year 键。

【讨论】:

以上是关于Swift JSON解码器类型不匹配错误的主要内容,如果未能解决你的问题,请参考以下文章

当您不知道 Swift 中的项目类型时,如何解码嵌套的 JSON 数据? [复制]

通过使用 Alamofire 和解码获取 JSON - Swift 4

使用包含不同类型字典的 Swift 解码 JSON

使用混合类型和混合键控/非键控在 Swift 中解码 JSON

Swift Json 解码不确定传入数据

仅在运行时知道类型时的 Swift 4 JSON 解码