Search code examples
iosjsonswiftnsjsonserialization

iOS swift - working with response from API


I am very new to Swift and iOS development. And I am wondering how to do something relatively simple if I was using JavaScript.

I am making a call to an API that is returning the following. Excuse the formatting but it is directly copied from the Xcode console.

["type": success, "value": <__NSArrayI 0x600000030340>(
       {
          categories = ();
          id = 155;
          joke = "Chuck Norris does not &quot;style&quot; his hair. It lays perfectly in place out of sheer terror.";
       },
       {
            categories = (nerdy);
            id = 69;
            joke = "Scientists have estimated that the energy given off during the Big Bang is roughly equal to 1CNRhK (Chuck Norris Roundhouse Kick).";
       }
    )
]

I want to loop over the response and add to an array. In JavaScript it would look like the following:

let jokes = [];
response.value.forEach(item => {
   jokes.push(item.joke)
})

It doesn't have to be exactly like the above. I am confident using loops in swift and appending to an array. What I am struggling to do is access the jokes in the value array returned from the API.

My controller looks like the following:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: "http://api.icndb.com/jokes/random/2")
        URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
            guard let data = data, error == nil else { return }
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
                print(json["value"])
                // not sure how to access each joke in the array here
            } catch let error as NSError {
                print(error)
            }
        }).resume()
    }
}

Solution

  • You can try

    if let va = json["value"] as? [[String:Any]] {
       va.forEach { print($0["joke"]) }
    }
    

    I would prefer to write a Codable structs for this

    struct Root: Codable {
        let type: String
        let value: [Value]
    }
    
    struct Value: Codable {
        let categories: [Category]
        let id: Int
        let joke: String
    }
    
    struct Category: Codable {
    }
    

    let res = try? JSONDecoder().decode(Root.self,from:data)
    print(res.value)