Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reload data of UITableView in background

In my app, I have a UITableViewController.

Its tableView is divided in 3 sections.

I download datas for each of those sections from my server. To do this, I have 3 functions (for example f1 f2 and f3). Each updates a corresponding NSArray, used as data source for my table.

Now what I want is to reload datas using this functions and refresh my tableView once this 3 functions are done, but without disturbing the user.

I'm not used with asynchronous request, blocks, threads etc... and I'm looking for tips.

Actually, here is what I do :

-(void)viewDidLoad
{
    //some settings

    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(reloadDatas) userInfo:nil repeats:YES];

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        [self reloadDatas];
    });
}

-(void)reloadDatas
{
    dispatch_queue_t concurrentQueue = dispatch_get_main_queue();
    dispatch_async(concurrentQueue, ^{
        [self f1];
        [self f2];
        [self f3];
        [myDisplayedTable reloadData];
    });
}

-(void)f1
{
    //load datas with a url request and update array1
}
-(void)f2
{
    //load datas with a url request and update array2
}
-(void)f3
{
    //load datas with a url request and update array3
}

But here, my tableView is "frozen" until it is refreshed.

I don't care about the order of execution of f1 f2 and f3, but I need to wait for this 3 functions to be done before refresh my tableView.

Thanks for your help.

EDIT

Thanks for all your answers.

Here is the working solution :

As mros suggets, I removed the dispatch queue from the viewDidLoad, and replace in reloadDatas:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

with

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

And finally, I reload my table in a main thread

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });
like image 990
zbMax Avatar asked Jun 27 '13 16:06

zbMax


2 Answers

So your "background thread" is actually your main thread. You have to use dispatch_get_global_queue and specify a priority to actually get a different thread. Also, the dispatch async in viewDidLoad is useless as all view controller lifecycle methods are called in the main thread. I would recommend doing something as follows in your f1, f2 and f3 methods:

Start by launching an asynchronous url request, then in the completion block, update arrayX and reload a particular section of your tableview. This way all three requests can happen simultaneously and the table just updates the necessary data when each one finishes. Alternatively, if you only want to reload once, just replace the concurrentQueue variable you have with a background thread and then perform [tableView reloadData] on the main thread.

like image 196
mrosales Avatar answered Oct 18 '22 14:10

mrosales


The previous answers are absolutely right. However your implementation of reloadDatas & viewDidLoad is a bit problematic.

Just to clarify:

You want to complete the time consuming data loading stuff in a background thread, then update the UI/Cells when your data is ready on the main thread.

Like so:

  -(void)viewDidLoad
    {
       dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.backgroundQueue", NULL);
        dispatch_async(concurrentQueue, ^{
            [self reloadDatas];
        });
    }

-(void)reloadDatas
{
    // Expensive operations i.e pull data from server and add it to NSArray or NSDictionary
      [self f1];
      [self f2];
      [self f3];

    // Operation done - now let's update our table cells on the main thread  

    dispatch_queue_t mainThreadQueue = dispatch_get_main_queue();
    dispatch_async(mainThreadQueue, ^{

        [myDisplayedTable reloadData]; // Update table UI
    });
}
like image 28
smaura777 Avatar answered Oct 18 '22 14:10

smaura777