debugDescription: “Expected to decode Array<Any> but found a dictionary instead.”, underlyingError: nil)

北战南征 提交于 2019-12-01 09:30:21

问题


I want to load an online json file into my application, but I am running into this error:

typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

I have looked on stackoverflow but other sollutions didn't help to solve mine.

My json

My datamodel:

import Foundation

struct Initial: Codable {
    let copyright: String
    let totalItems: Int
    let totalEvents: Int
    let totalGames: Int
    let totalMatches: Int
    let wait: Int
    let dates: [Dates]
}

struct Dates: Codable {
    let date: String
    let totalItems: Int
    let totalEvents: Int
    let totalGames: Int
    let totalMatches: Int
    let games: [Game]
}

struct Game: Codable {
    let gamePk: Int
    let link: String
    let gameType: String
    let season: String
    let gameDate: String
    let status: Status
    let teams: Team
    let venue: Venue
    let content: Content
}

struct Status: Codable {
    let abstractGameState: String
    let codedGameState: Int
    let detailedState: String
    let statusCode: Int
    let startTimeTBD: Bool
}

struct Team: Codable {
    let away: Away
    let home: Home
}

struct Away: Codable {
    let leagueRecord: LeagueRecord
    let score: Int
    let team: TeamInfo
}

struct Home: Codable {
    let leagueRecord: LeagueRecord
    let score: Int
    let team: TeamInfo
}

struct LeagueRecord: Codable {
    let wins: Int
    let losses: Int
    let type: String
}

struct TeamInfo: Codable {
    let id: Int
    let name: String
    let link: String
}

struct Venue: Codable {
    let name: String
    let link: String
}

struct Content: Codable {
    let link: String
}

and here is my viewcontroller

import UIKit

class TodaysGamesTableViewController: UITableViewController {
    var todaysGamesURL: URL = URL(string: "https://statsapi.web.nhl.com/api/v1/schedule")!

    var gameData: [Dates] = []
    let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)

    override func viewDidLoad() {
        super.viewDidLoad()
        loadTodaysGames()
    }

    func loadTodaysGames(){
        print("load Games")

        view.addSubview(activityIndicator)
        activityIndicator.frame = view.bounds
        activityIndicator.startAnimating()

        let todaysGamesDatatask = URLSession.shared.dataTask(with: todaysGamesURL, completionHandler: dataLoaded)

        todaysGamesDatatask.resume()
    }

    func dataLoaded(data:Data?,response:URLResponse?,error:Error?){
        if let detailData = data{
            print("detaildata", detailData)
            let decoder = JSONDecoder()
            do {
                let jsondata = try decoder.decode([Dates].self, from: detailData)
                gameData = jsondata //Hier .instantie wil doen krijg ik ook een error

                DispatchQueue.main.async{
                    self.tableView.reloadData()
                }
            }catch let error{
                print(error)
            }
        }else{
            print(error!)
        }
    }

回答1:


Please learn to understand the decoding error messages, they are very descriptive.

The error says you are going to decode an array but the actual object is a dictionary (the target struct).

First take a look at the beginning of the JSON

{
  "copyright" : "NHL and the NHL Shield are registered trademarks of the National Hockey League. NHL and NHL team marks are the property of the NHL and its teams. © NHL 2018. All Rights Reserved.",
  "totalItems" : 2,
  "totalEvents" : 0,
  "totalGames" : 2,
  "totalMatches" : 0,
  "wait" : 10,
  "dates" : [ {
    "date" : "2018-05-04",

It starts with a { which is a dictionary (an array is [) but you want to decode an array ([Dates]), that's the type mismatch the error message is referring to.


But this is only half the solution. After changing the line to try decoder.decode(Dates.self you will get another error that there is no value for key copyright.

Look again at the JSON and compare the keys with the struct members. The struct whose members match the JSON keys is Initial and you have to get the dates array to populate gameData.

let jsondata = try decoder.decode(Initial.self, from: detailData)
gameData = jsondata.dates



回答2:


The JSON is represented by your Initial struct, not an array of Dates.

Change:

let jsondata = try decoder.decode([Dates].self, from: detailData)

to:

let jsondata = try decoder.decode(Initial.self, from: detailData)



回答3:


Correct Answer is done previously from my two friends

but you have to do it better i will provide solution for you to make code more clean and will give you array of Dates

here is your model with codable

   import Foundation

struct Initial: Codable {
    let copyright: String
    let totalItems: Int
    let totalEvents: Int
    let totalGames: Int
    let totalMatches: Int
    let wait: Int
    let dates: [Dates]
}

struct Dates: Codable {
    let date: String
    let totalItems: Int
    let totalEvents: Int
    let totalGames: Int
    let totalMatches: Int
    let games: [Game]
}

struct Game: Codable {
    let gamePk: Int
    let link: String
    let gameType: String
    let season: String
    let gameDate: String
    let status: Status
    let teams: Team
    let venue: Venue
    let content: Content
}

struct Status: Codable {
    let abstractGameState: String
    let codedGameState: Int
    let detailedState: String
    let statusCode: Int
    let startTimeTBD: Bool
}

struct Team: Codable {
    let away: Away
    let home: Home
}

struct Away: Codable {
    let leagueRecord: LeagueRecord
    let score: Int
    let team: TeamInfo
}

struct Home: Codable {
    let leagueRecord: LeagueRecord
    let score: Int
    let team: TeamInfo
}

struct LeagueRecord: Codable {
    let wins: Int
    let losses: Int
    let type: String
}

struct TeamInfo: Codable {
    let id: Int
    let name: String
    let link: String
}

struct Venue: Codable {
    let name: String
    let link: String
}

struct Content: Codable {
    let link: String
}

// MARK: Convenience initializers

extension Initial {
    init(data: Data) throws {
        self = try JSONDecoder().decode(Initial.self, from: data)
    }

}

And Here is Controller Will make solution more easy

class ViewController: UIViewController {
    var todaysGamesURL: URL = URL(string: "https://statsapi.web.nhl.com/api/v1/schedule")!

    var gameData: Initial?
    let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)





    override func viewDidLoad() {
        super.viewDidLoad()

        self.loadTodaysGames()

    }

        func loadTodaysGames(){
    print("load Games")
    let todaysGamesDatatask = URLSession.shared.dataTask(with: todaysGamesURL, completionHandler: dataLoaded)
    todaysGamesDatatask.resume()
}
func dataLoaded(data:Data?,response:URLResponse?,error:Error?){
    if let detailData = data {
        if  let inital = try? Initial.init(data: detailData){
           print(inital.dates)
        }else{
             // print("Initial")
        }
    }else{
        print(error!)
    }
}

}


来源:https://stackoverflow.com/questions/50179922/debugdescription-expected-to-decode-arrayany-but-found-a-dictionary-instead

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!