Peter
Peter

Reputation: 1359

Variable not being set in an asynchronously called block

I've got the following code, which connects to a server (actually, my own machine right now), downloads some data, unserializes it, and assigns it to a global variable.

UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
MasterViewController *masterController = [navController.viewControllers objectAtIndex:0]; // masterController is a UITableViewController subclass
NSMutableArray *surveys = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:8000/testapp/survey-data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *rep, NSData *d, NSError *err) {
    if(d) {
        NSMutableArray *allSurveys = [NSJSONSerialization JSONObjectWithData:d options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil];
        for(NSMutableArray *item in allSurveys) {
            NSString *title = [item objectAtIndex:[item count] - 1];
            [item removeLastObject];
            Survey *survey = [[Survey alloc] initWithArray:item title:title];
            [surveys addObject:survey];
        }
        masterController.surveys = surveys;


        NSLog(@"%@", [masterController.surveys description]);
    }
}];

Unfortunately, it is not working. The NSLog() (inside the handler block) prints out all the data, as expected. Clearly the connection is working. The view, however, doesn't get updated, and the rows are all blank. Is this happening because the block is getting called after the download is finished? How can I avoid this?

It also seems like it might be caused by setting a variable in the block. I looked through Apple's documentation, though, and it seems like this shouldn't be a problem, because I'm setting an array through the reference to masterViewController. Am I wrong?

I should note that I tried rewriting this to use a [NSURLConnection sendSynchronousRequest:returningResponse:error:, which worked well. However, a synchronous request could be a terrible idea if the network is slow or down, so I really need to get this working asynchronously.

Upvotes: 1

Views: 255

Answers (2)

sheraza
sheraza

Reputation: 511

AsynchronousRequest does not use main thread where the UI update happens, so for the UI update use this:

dispatch_async(dispatch_get_main_queue(), ^{ 
    //UI update here    
});

Upvotes: 1

lnafziger
lnafziger

Reputation: 25740

Since your view loads before you get the data, you need to call reloadData on your table view after your data arrives.

To prevent other problems, make sure that you are doing this on the main thread as UIKit classes are not thread safe.

Upvotes: 1

Related Questions