wander
wander

Reputation: 712

Blocks and GCD: Asynchronous data collection

I'm starting out with JSON (totally new to web services) and am doing this to collect the data from the Wunderground API. This -synchronous- code works for me:

NSDictionary *weatherData;

NSString *urlString;
if (self.apiKey) {
    urlString = [@"http://api.wunderground.com/api/" stringByAppendingString:self.apiKey];
}
urlString = [urlString stringByAppendingString:@"/conditions/q/CA/San_Francisco.json"];;
NSURL *url = [NSURL URLWithString:urlString];
NSData *jasonData = [NSData dataWithContentsOfURL:url];

NSError *error;
weatherData = [NSJSONSerialization JSONObjectWithData:jasonData options:0 error:&error];

if (error) {
    NSLog(@"Error creating JSON Object, error description  = %@", [error localizedDescription]);
}

return weatherData;
// returns a dictionary 

But this doesn't:

__block NSDictionary *weatherData;
dispatch_queue_t weatherDataQueue = dispatch_queue_create("weatherDataQueue", NULL);
dispatch_async(weatherDataQueue, ^{
    NSString *urlString;
    if (self.apiKey) {
        urlString = [@"http://api.wunderground.com/api/" stringByAppendingString:self.apiKey];
    }
    urlString = [urlString stringByAppendingString:@"/conditions/q/CA/San_Francisco.json"];;
    NSURL *url = [NSURL URLWithString:urlString];
    NSData *jasonData = [NSData dataWithContentsOfURL:url];

    NSError *error;
    weatherData = [NSJSONSerialization JSONObjectWithData:jasonData options:0 error:&error];

    if (error) {
        NSLog(@"Error with creating JSON Object, error description %@", [error localizedDescription]);
    }
});

NSLog(@"weatherData = %@", weatherData);

return weatherData;
// returns NULL

Now, I realize that this probably has to do with the fact that when I return weatherData, the code in the dispatched block hasn't run yet. I would greatly appreciate it if anybody could help me figure out how to fix this.

Upvotes: 0

Views: 175

Answers (3)

Ben Coffman
Ben Coffman

Reputation: 1740

I would suggest posting a NSNotification and then set up a listener for that notification and execute the necessary code on weatherData at that point.

Though I do like @bbum suggestion the best.

Upvotes: 0

shawnwall
shawnwall

Reputation: 4607

May I give a suggestion that will simplify your life greatly - use AFNetworking for network operations such as this.

Alternatively you need to pass in a callback block to your function that can then execute with the weatherData value. Your assumption regarding the weatherData error is correct.

Upvotes: 0

bbum
bbum

Reputation: 162712

When doing something asynchronously, you need to trigger the "hey, I've downloaded the data!" from the asynchronously executing code.

That is, the end of your block that loads data would do something like:

 dispatch_async(dispatch_get_main_queue(), ^{
      ... do whatever is necessary to load/display the data in the UI here ...
 });

Upvotes: 4

Related Questions