0

I am receiving and trying to parse a json file that contains event data. It is a dictionary of dictionaries organized like so with a random event id # as the key to each:

{
    "19374176-122" : 
    {
        "event_title" : "Cool Fun Thing to Do",
        "description" : "Have fun and do something cool",
        "time_start" : "13:00:00",
        "time_end" : "14:00:00"
    },
    "9048-5761634" :
    {
        "event_title" : "Nap Time",
        "description" : "Lay down and go to sleep.",
        "time_start" : "15:00:00",
        "time_end" : "16:00:00"
    }
}

I have created a structure for the event

struct Event: Codable{
    let event_title: String
    let description: String
    let time_start: String
    let time_end: String
}

And tried to decode

do{
    let eventData = try JSONDecoder().decode([Event].self, from: data)    
        DispatchQueue.main.async {
            print(eventData)
            //self.events = eventData
            self.collectionView?.reloadData()
        }
    } catch let jsonError{
        print(jsonError)
}

But I get the error that I'm trying to decode an array but getting a dictionary

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

So then I tried to create a structure for the Root of the json file

struct Root: Codable {
    let event_number: Event
}

And decode that

do{
    let eventData = try JSONDecoder().decode(Root.Event.self, from: data)    
        DispatchQueue.main.async {
            print(eventData)
            //self.events = eventData
            self.collectionView?.reloadData()
        }
    } catch let jsonError{
        print(jsonError)
}

But since the key for this dictionary of dictionaries is not actually "event_number" I can't get that data

keyNotFound(CodingKeys(stringValue: "event_number", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"event_number\", intValue: nil) (\"event_number\").", underlyingError: nil))

What am I missing here? I feel like this should be relatively simple, I must just be completely overlooking something.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Case Silva
  • 466
  • 7
  • 26
  • Look at this awesome suggestion: https://stackoverflow.com/questions/54129682/use-swift-codable-to-decode-json-with-values-as-keys/54131007#54131007 – vadian May 10 '19 at 20:46

1 Answers1

1

You need

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let eventData = try decoder.decode([String:Event].self, from: data)   

struct Event: Codable {
   let eventTitle, description, timeStart, timeEnd: String
}

{} means a dictionary and [] means an array

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • 1
    Point of clarification: In **JSON**, `{}` means dictionary and `[]` means an array. – Duncan C May 10 '19 at 21:41
  • How can I get the event itself after using this method? When I print the eventData now, it gives me an array of ```"RandomKey": Package.Event(eventTitle: "blah blah", description: "blah blah", timeStart: "blah blah", timeEnd: "blah blah")```. but I need to be able to pass each event to a cell view – Case Silva May 13 '19 at 13:27
  • Specifically, trying to set ```self.events = eventData``` fails saying that it ```Cannot assign value of type '[String:Event]' to type '[Event]?'``` – Case Silva May 13 '19 at 13:33
  • do `self.events = Array(eventData.values)` – Shehata Gamal May 13 '19 at 13:34