Nenad Savic
Nenad Savic

Reputation: 77

Expected to decode String but found a dictionary instead

I can not pars data from fixtures array, every time I get a mistake

error in console log:

downloaded
Error info: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [LiveZscores.EventsFull.(CodingKeys in _B768B663C3B4834FEE8438F5C59CA80A).fixtures, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)), LiveZscores.EventsData.(CodingKeys in _B768B663C3B4834FEE8438F5C59CA80A).result], debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil))

My code:

ViewController.swift

final let url = URL(string: "http://api.football-data.org/v1/fixtures")

override func viewDidLoad() {
    super.viewDidLoad()

    downloadJson()

}

func downloadJson() {
    guard let downloadURL = url else { return }

    URLSession.shared.dataTask(with: downloadURL) { (data, urlResponse, error) in
        guard let data = data, error == nil, urlResponse != nil else {
            print ("something")
            return
        }
        print ("downloaded")
        do {
            let decoder = JSONDecoder()
            let events = try decoder.decode(EventsFull.self, from: data)
            print (events.fixtures)

        }catch {
            print("Error info: \(error)")
        }


    }.resume()

}

Events.swift

class EventsFull: Codable {
    let fixtures: [EventsData]

    init(fixtures: [EventsData]) {
        self.fixtures = fixtures
    }
}

class EventsData: Codable {

    let date: String
    let status: String
    let matchday: Int
    let homeTeamName: String
    let awayTeamName: String
    let result: String
    let odds: Double

    init(date: String, status: String, matchday: Int, homeTeamName: String, awayTeamName: String, result: String, odds: Double) {

        self.date = date
        self.status = status
        self.matchday = matchday
        self.homeTeamName = homeTeamName
        self.awayTeamName = awayTeamName
        self.result = result
        self.odds = odds
    }

}

Upvotes: 2

Views: 8875

Answers (1)

vadian
vadian

Reputation: 285230

Please learn to read error messages, especially Codable messages are very easy to read.

This is the message a bit more structured

typeMismatch(Swift.String, 
         Swift.DecodingError.Context(codingPath: [LiveZscores.EventsFull.(CodingKeys in _B768B663C3B4834FEE8438F5C59CA80A).fixtures, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)), 
                                                  LiveZscores.EventsData.(CodingKeys in _B768B663C3B4834FEE8438F5C59CA80A).result], debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil))

Swift.String is the expected type in the struct / class

The most significant codingPath information is

codingPath: [LiveZscores.EventsFull.fixtures, 
             LiveZscores.EventsData.result], debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil))

The error occurred in the key result in the struct EventsData which is in the struct EventsFull for key fixtures and the message tells you clearly what's wrong

Take a look at the JSON: The value for key result is a dictionary which can be represented by another struct.


Normally you don't need a class inherited from NSObject to decode JSON, a struct is sufficient and you don't need an initializer, the Codable protocol provides the initializer.

All keys which can be null must be declared as optional, both keys in Result and the key odds in EventsData can be null.

struct EventsFull: Decodable {
    let fixtures: [EventsData]
}

struct EventsData: Decodable {
    let date: String
    let status: String
    let matchday: Int
    let homeTeamName: String
    let awayTeamName: String
    let result: Result
    let odds: Double?
}

struct Result : Decodable {
    let goalsHomeTeam : Int?
    let goalsAwayTeam : Int?
}  

Upvotes: 3

Related Questions