toddbranch
toddbranch

Reputation: 82

Updating UI after completion of background thread

I'm implementing a simple twitter client for the iPhone using a UITableView. I fetch the picture of each twitter user in my feed when their cell appears in tableView: cellForRowAtIndexPath:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    UIImage *profileImage = [tweet.user getProfileImageDataInContext:self.fetchedResultsController.managedObjectContext];
    dispatch_async(dispatch_get_main_queue(), ^{
        cell.imageView.image = profileImage;
    });
});

Here is the code to fetch the image:

    if (!self.profileImage) 
{
    sleep(2);
    self.profileImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.profileImageURL]];
    //// if we recently scheduled an autosave, cancel it
    [TwitterUser cancelPreviousPerformRequestsWithTarget:self selector:@selector(autosave:) object:context];
    // request a new autosave in a few tenths of a second
    [TwitterUser performSelector:@selector(autosave:) withObject:context afterDelay:0.2];
}
return [UIImage imageWithData:self.profileImage];

Here is the error I'm getting:

twitterClient[10743:15803] bool _WebTryThreadLock(bool), 0x59bac90: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...

I think it's also worth mentioning that this happens when I scroll through the tableview very quickly when it hasn't been populated yet.

I would like the main UI to update upon completion of the download. The actual twitter app for iPhone does this quite well.

Any suggestions?

Upvotes: 2

Views: 601

Answers (2)

Sahil
Sahil

Reputation: 1268

You're using GCD fine, your crash is happening because you're calling dataWithContentsOfURL in a background thread, which is not thread safe.

See: Does -dataWithContentsOfURL: of NSData work in a background thread?

Upvotes: 1

Noah Witherspoon
Noah Witherspoon

Reputation: 57149

What’s the crash? A pretty standard pattern for things like this is

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // do background stuff
    dispatch_async(dispatch_get_main_queue(), ^{
        // do main-queue stuff, like updating the UI
    });
});

Upvotes: 4

Related Questions