KingTim
KingTim

Reputation: 1301

Using the same coding key in two structs when decoding JSON

I'm making a small app to practice parsing JSON into a tableview, and I'm using the Ticketmaster API. This is the JSON, and these are the structs that I have set up:

struct Welcome: Decodable {
    let embedded: WelcomeEmbedded
    enum CodingKeys: String, CodingKey{
        case embedded = "_embedded"
    }
}

struct WelcomeEmbedded: Decodable {
    let events: [Event]
}

struct Event: Decodable {
    let name: String
    let dates: Dates
    let eventUrl: String?
    let embedded: EventEmbedded

    enum CodingKeys: String, CodingKey {
        case name
        case dates
        case eventUrl
        case embedded = "_embedded"
    }
}

struct EventEmbedded: Decodable {
    let venue: Venue
}

struct Dates: Decodable {
    let start, end: End
}

struct Venue: Decodable {
    let name: String
}

Before adding in the value let embedded: EventEmbedded to the Event struct, things worked fine, but after adding in that line, when running the app I get an error:

Error decoding JSON: typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "_embedded", intValue: nil), CodingKeys(stringValue: "events", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "_embedded", intValue: nil), CodingKeys(stringValue: "venue", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

I'm wondering how adding that line alone results in an error, is it anything to do with the fact that I have a value named embedded in two structs (Welcome and Event), and both use the coding key _embedded?

For some added detail, to parse the JSON I have a variable var eventData = [Event]() and call this function in viewDidLoad to populate eventData with the necessary data:

    fetchData(url: apiUrl) { (result: FetchResult<Welcome>) -> (Void) in

        switch result {
        case .success(let object): self.eventData = object.embedded.events
        case .failure(let error): print("\nError decoding JSON: \(error)\n\n")
        }
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }

The error also says CodingKeys(stringValue: "venue", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.. But looking at the JSON, the data under venue is structured the same way as the rest of the values, and they don't give me an error.

What can I do differently here to get back on track?

Upvotes: 0

Views: 308

Answers (1)

vadian
vadian

Reputation: 285074

Please learn to read Codable errors. They are very, very, very descriptive.

Error decoding JSON: typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "_embedded", intValue: nil), CodingKeys(stringValue: "events", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "_embedded", intValue: nil), CodingKeys(stringValue: "venue", intValue: nil)], debugDescription: "Expected to decode Dictionary but found an array instead.", underlyingError: nil))

  • typeMismatch is the error type
  • CodingKeys(stringValue: "_embedded", CodingKeys(stringValue: "events"), CodingKeys(stringValue: "_embedded"), CodingKeys(stringValue: "venue") is the key path (_embedded/events/_embedded/venue)
  • Expected to decode Dictionary<String, Any> but found an array instead is the error message.

    • Expected is the wrong type you proposed.
    • found is the actual type.

      A dictionary is the struct, an array is an array of the struct.

Change EventEmbedded to

struct EventEmbedded: Decodable {
    let venue: [Venue]
}

Upvotes: 2

Related Questions