1

I am parsing a feed of json data representing events. On a day where there ARE events, the json feed will be a Dictionary of Dictionaries, and looks something like this:

{
    "19374176" : 
    {
        "event_title" : "Cool Fun Thing to Do",
        "event_description" : "Have fun and do something cool",
        "event_start_time" : "13:00:00",
        "event_end_time" : "14:00:00"
    },
    "90485761634" :
    {
        "event_title" : "Nap Time",
        "event_description" : "Lay down and go to sleep.",
        "event_start_time" : "15:00:00",
        "event_end_time" : "16:00:00"
    }
}

I have a structure set up and I can decode and use this information the way I would like to currently with this code that is part of a larger function:

URLSession.shared.dataTask(with: url){(data, response, error) in
        if error != nil {
            print("session error: ", error!.localizedDescription)
        }

        guard let data = data else { return }

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

            DispatchQueue.main.async{
                self.events = Array(eventData.values).sorted(by: {$0.timeStart < $1.timeStart
                })

                self.updateView()
                self.refreshControl.endRefreshing()
                self.activityIndicatorView.stopAnimating()
            }
        } catch DecodingError.typeMismatch(let type, let context){
            //No Dictionary of Events in Data
            print("key:", type, "context: ", context)
        } catch let jsonError{
            print("json error: ", jsonError)
        }
    }.resume()
}

My issue right now is that, on days where there no events, the json feed is an empty Array:

[]

This causes a type mismatch which I handle, but if I try to call the updateView, refreshControl, or activityIndicatorView's functions from the catch, I get an error that I cannot call them outside the main thread.

I tried to do nested try blocks to assign the eventData variable (first to see if it is an [String] ((empty array, no events)) and then to [String:Any] ((array with values of events))), but that gave me an error for the URLSession.

Is there a better approach to this to see if the json is an empty array vs a populated dictionary of my Event values and update the views regardless?

4
  • Make sure to call any UI related calls on the main thread, inside a DispatchQueue.main.async closure. Commented May 16, 2019 at 14:21
  • Yes, that is present in my currently working code, but I also need to call those events if my assigning of eventData fails Commented May 16, 2019 at 14:22
  • As Koen said, if this is what you have to do. Simply run all UI methods on the main queue inside the block. write another function that runs all those calls on the main thread and then call that function in the N places you need too. However if its in your power to change, having a dictionary for the success case and an empty array in the error case, is a huge bad practise issue. API's should return 1 and only 1 type Commented May 16, 2019 at 14:24
  • Yeah, unfortunately I have absolutely no control on what data is returned. That would make this much more straight forward if I could Commented May 16, 2019 at 14:29

1 Answer 1

3

Try refreshing them outside of any blocks

do { 
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    print(data)
    var eventData = try decoder.decode([String:Event].self, from: data)
    self.events = Array(eventData.values).sorted(by: {$0.timeStart < $1.timeStart

} catch DecodingError.typeMismatch(let type, let context){
    //No Dictionary of Events in Data
    print("key:", type, "context: ", context)
} catch let jsonError{
    print("json error: ", jsonError)
}

DispatchQueue.main.async{
    self.updateView()
    self.refreshControl.endRefreshing()
    self.activityIndicatorView.stopAnimating()
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.