Reputation: 548
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?
Upvotes: 1
Views: 420
Reputation: 19164
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)
}
}
}
Upvotes: 2
Reputation: 38843
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)
Upvotes: 1