在后台重新加载UITableView的数据

时间:2013-06-27 16:11:27

标签: ios asynchronous uitableview

在我的应用程序中,我有一个UITableViewController。

它的tableView分为3个部分。

我从服务器下载每个部分的数据。为此,我有3个函数(例如f1 f2和f3)。每个都更新一个相应的NSArray,用作我的表的数据源。

现在我想要的是使用这个函数重新加载数据,并在完成这3个功能后刷新我的tableView,但不会打扰用户。

我没有使用异步请求,块,线程等......而且我正在寻找提示。

实际上,这就是我的工作:

-(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
}

但是在这里,我的tableView被“冻结”,直到它被刷新。

我不关心f1 f2和f3的执行顺序,但我需要等待刷新tableView之前完成这三个函数。

感谢您的帮助。

修改

感谢您的所有答案。

以下是工作解决方案:

正如mros的建议,我从viewDidLoad中删除了调度队列,并在reloadDatas中替换:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

最后,我在主线程中重新加载我的表

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });

4 个答案:

答案 0 :(得分:5)

所以你的“后台线程”实际上就是你的主线程。您必须使用dispatch_get_global_queue并指定实际获得不同线程的优先级。此外,viewDidLoad中的dispatch async是无用的,因为在主线程中调用了所有视图控制器生命周期方法。我建议你在f1,f2和f3方法中做如下的事情:

首先启动异步URL请求,然后在完成块中更新arrayX并重新加载tableview的特定部分。这样,所有三个请求都可以同时发生,并且表只是在每个请求完成时更新必要的数据。或者,如果您只想重新加载一次,只需用后台线程替换concurrentQueue变量,然后在主线程上执行[tableView reloadData]

答案 1 :(得分:3)

之前的答案绝对正确。但是你执行reloadDatas& viewDidLoad有点问题。

只是为了澄清:

您希望在后台线程中完成耗时的数据加载,然后在主线程上准备好数据时更新UI / Cells。

像这样:

  -(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
    });
}

答案 2 :(得分:2)

reloadDatas方法中,您应该更改此行:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

要:

dispatch_queue_t concurrentQueue = dispatch_queue_create("some queue", NULL);

但是当你打电话给[myDisplayedTable reloadData]时,你需要在主队列中调用这个操作。

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });

答案 3 :(得分:1)

另一件事。从服务器中提取数据并更新表格单元格非常常见。 这里不需要队列或计时器。 这是另一种结构。

说你从你的服务器中拔出mp3: 您的模型类是:Music.h / m 你的模型管理器是:MusicManager.h / m(Singleton) - 它将包含一个音乐对象数组 - 单例基本上是你的数据源; 最后你的UItableViewController:MusicTableVC.h / m

在MusicManager.h / m中:您有 NSMutableArray ,它将加载您从服务器提取的Music.h对象。您可以在应用程序加载后立即执行此操作,甚至无需等待TableViewController。

在MusicManager中你有一些帮助方法来添加或删除mutableArray中的项目并提供计数,当然还有你的网络方法。

最后:在您的网络代码中发布通知。您的UITableViewController应该监听/观察该通知并重新加载"相应

 [[NSNotificationCenter defaultCenter] postNotificationName:@"NewMusicAdded" object:nil];

您从服务器查询数据,将数据解析为音乐对象,将它们添加到NSMutable数组并发布通知以让表自行更新。

漂亮的标准食谱。