Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift JSONDecoder typeMismatch error

Tags:

json

swift

I'm trying to use JSONDecoder to convert a JSON to Structs in Swift, so I wrote all the Structs, revised them for hours, and it still gives me this error. I don't know if there is a way to see the line that gives this. I'll post my struct below and the Json File links right after.

The complete error description is:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

//  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

like image 774
Breno Rios Ramos Avatar asked Dec 29 '17 13:12

Breno Rios Ramos


2 Answers

You're probably doing this right now:

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

which is fine for the response with a top-level Object.

To decode JSON responses that are top-level Arrays, use code like this instead:

let decoder = JSONDecoder()
let repos = decoder.decode([Repo].self, from: data)
like image 98
Gereon Avatar answered Nov 04 '22 19:11

Gereon


If you have a problematic JSON, which can contain number or string for some keys, you can decode object without that property and manually set that property after decoding.

For example, I have a Vehicle class inside HistoryItem. In Vehicle model_year can be empty String or non empty Int. Here I am decoding modelYear manually using NSDictionary and trying to get Int. Swift 4 cannot do it automatically.

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

This is my Vehicle class that is contained inside 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"
    }
}

As you see, there is no model_year key in CodingKeys.

like image 35
Denis Kutlubaev Avatar answered Nov 04 '22 19:11

Denis Kutlubaev