1

I'm trying to get JSON from a service in Swift 2

https://someapidomain.com/entries.json 
[
1212,
1234,
2934,
....
]

https://someapidomain.com/entry/entry_id.json 
{
  "key1": "value1",
  "key2": 23,
  "key3": "value3,
   ...
}

Service must return:
[
 {
  "key1": "value1",
  "key2": 23,
  "key3": "value3,
   ...
},
{
  "key1": "value1",
  "key2": 23,
  "key3": "value3,
   ...
},
....
]


struct ExampleService {

private static let baseURL = "https://someapidomain.com/"
private static let entries_per_page = 10

private static func getJSONResponse(url: String, callback: (AnyObject) -> () ){

        let request = NSMutableURLRequest(URL: NSURL(string: url)!)
        let session = NSURLSession.sharedSession()

        request.HTTPMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        let task = session.dataTaskWithRequest(request, completionHandler: {
            data, response, err -> Void in

            do {
                let jsonResponse = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
                callback(jsonResponse)

            }catch {
                print("Error processing json")
            }

        })
        task.resume()


    }

 static func getEntries(url: String, callback: ([[String: AnyObject]]) -> ()) {

        var entries: [[String:AnyObject]] = []
        let apiURL = baseURL + url

        getJSONResponse(apiUrl) { (response) in
            if let entryIds = response as? Array<Int> {
                for entryId in storyIds[0..<entries_per_page] {
                    let entryURL = baseURL + "/entry/\(entryId).json"

                    getJSONResponse(entryURL) { (response) in

                        if let entry = response as? [String: AnyObject] {

                           print(entry)
                           entries.append(entry)

                        }

                    }

                }

               callback(entries)

            }
        }


    }

}


}

Now when I call the service I get empty array

ExampleService.getEntries("/entries.json") { (response) in
     print(response)  // prints []
}

Whereas individual entries inside the loop prints the json. I think its because the callback is getting called before the for loop excecution is finished.

How can I fix this?

4
  • In getEntries(), you add the base URL to entryURL but not to the request to get Entry ID's. Commented Dec 2, 2015 at 17:17
  • @PriceRingo corrected. Thanks! Commented Dec 2, 2015 at 17:48
  • @rashwan-l Please stop adding the ios tag to questions that are not directly related to iOS and could work for other Swift supporting platforms. Thank you. Commented Jan 3, 2016 at 22:51
  • 1
    @EricD. I´ll keep that in mind, thanks for the feedback. Commented Jan 3, 2016 at 23:03

2 Answers 2

2

The modified function getEntries sketches how you can accomplish this with a dispatch_group.

Additionally, you MUST ensure your function getJSONResponse always calls the completion handler, even in the case it fails. This is because, you must ensure the function calls dispatch_enter and dispatch_leave are balanced.

I would recommend to modify the getEntries function as well in that sense, that is always call the completion handler even when it fails. Modify the signature of the completion handler accordingly.

static func getEntries(url: String, callback: ([[String: AnyObject]]) -> ()) {

    var entries: [[String:AnyObject]] = []

    getJSONResponse(url) { (response) in
        let queue = dispatch_queue_create("myqueue", nil)
        let group = dispatch_group_create()
        if let entryIds = response as? Array<Int> {
            for entryId in entryIds {
                dispatch_group_enter(group)
                let entryURL = baseURL + "/entry/\(entryId).json"
                getJSONResponse(entryURL) { (response) in
                    if let entry = response as? [String: AnyObject] {
                        print(entry)
                        entries.append(entry)
                    }
                    dispatch_group_leave(group)
                }
            }
        }
        dispatch_group_notify(group, queue) {
            callback(entries)
        }
    }

}
Sign up to request clarification or add additional context in comments.

Comments

1

Use Grand Central Dispatch

Example below to create, enter and leave

let jsonGroup = dispatch_group_create()

    for x in json{
        dispatch_group_enter(getDeparturesGroup)

        // Some code...
    }

    dispatch_group_wait(jsonGroup, DISPATCH_TIME_FOREVER)

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.