Table view updates from NSNotification posts


#1

My app has a tableview with cells that can each call for a download of content to a singleton class.

As the download progresses the singleton posts notifications with the cell index path that should update its progress view which I have working, apart from one problem!

As soon as one cell asks for a download and starts to receive post notifications the UI freezes until that cell and finished receiving all posts?

So where I want to be able to tap random cells and see each of their progress views being updated I get stuck with basically doing one download at a time.

Here is what I do:

I make a call to add a request to the queue passing in the cell’s index

In the singleton class that does all the work I have this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
               
               // go make the call
               
               [self runRequest:queue];
            });

and in runRequest I have this:

         NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:q.name, @"name", q.cellrow, @"cell", nil];
         
         [[NSNotificationCenter defaultCenter] postNotificationName:kFileDidReceiveDataNotification object:nil userInfo:dict];

and in my view controller that listens to the posts I have this:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[[dict objectForKey:@"cell"] intValue] inSection:0];

[tView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:NO];

So I do get the individual cell updating in the table view as a response to the post notification, but I cannot select another cell while that download is taking place. In fact if I try to scroll the tableview it is frozen … until the download is complete and then jumps as a response to my attempts to move it.

I thought as I was using dispatch_async this would be avoided?

What have I missed?

Thansk


#2

As written, it looks like you’re posting your NSNotification on the same (background) thread where you’re making your service calls. I’m surprised that your notifications are being received at all - unless you’re listening for it on that thread then proceeding to also perform your UI work on that same (background) thread.

Don’t forget that you should never-ever-ever touch your user interface from any thread other than the main thread.

The most common pattern for this, when using dispatch_async, is to dispatch your work to another thread and then dispatch your UI update back to the main thread, as a nested dispatch:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

    // Make my synchronous service calls or do other heavy work

    // now that it's done...
    dispatch_async(dispatch_get_main_queue(), ^{
        // Update my UI, such as a call to [tableView reloadData] or whatever
    });
});