实现GCD后,TableView显示为空

时间:2012-07-23 22:42:59

标签: iphone xcode ios5 grand-central-dispatch

我正在尝试将盛大的中央调度合并到我的表格视图中。我有一个属性:NSArray *topPlaces

topPlaces是来自Flickr查询的字典数组。这需要一些时间来执行,所以我想把它放在一个单独的线程上。此表使用topPlaces填写表的每一行(注意:此表是加载应用程序时显示的第一个视图)。因为有几个方法调用了getTopPlaces,所以在topPlaces未初始化的情况下,我在getTopPlaces中进行了一个惰性实例化。我的代码目前:

- (NSArray *)getTopPlaces
{

   if (!_topPlaces)
      {
        dispatch_queue_t downloadrQueue = dispatch_queue_create("lister downloader", NULL);
        dispatch_async(downloadrQueue, ^{
            _topPlaces = [FlickrFetcher topPlaces];

            dispatch_async(dispatch_get_main_queue(), ^{
                NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"_content" ascending:YES];

                NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
                NSArray *flickrTopPlacesAlphabetic = [_topPlaces sortedArrayUsingDescriptors:sortDescriptors];

                _topPlaces = flickrTopPlacesAlphabetic;
            });
        });
        dispatch_release(downloadrQueue);
      }

   return _topPlaces;
}

我试图解决的主要问题是,当选择一行时,它会转移到新的表视图。但是当我选择一行时,它会冻结几秒钟,直到新表加载为止。我希望用户能够在选择行并准备segue时滚动。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

您可能会发现此示例项目很有用:https://github.com/akosma/async-uitableview/

答案 1 :(得分:1)

首先,以get开头的命名方法与Apple's coding guidelines相反。对于以get开头的命名方法,有一个罕见且具体的案例。

您的主要问题是您异步调度任务以填充_topPlaces并在异步调用填充它之前返回它。您可以使用dispatch_sync替换它,但是您将失去在GCD后台队列上处理的任何性能增益。相反,试试这个:

  1. 不要从此方法返回任何内容(无效)
  2. 将您的排序向上移动到downloadrQueue块(无需跳回主线程 - 排序成本高昂)
  3. 在主队列块中,在表视图上调用reloadData
  4. 在cellForRowAtIndexPath中,根据topPlaces
  5. 填充表格

    你的第二个问题是,当你应该坚持下去时,你正在创建和销毁队列。尝试将downloadrQueue存储为属性并将其保留在表的视图控制器的生命周期中。

答案 2 :(得分:1)

为了更有效地实现这一点,@Jacob建议您执行类似的操作(将your_table_view_object替换为实际对象的ref):

- (void)updateTopPlaces
{

   if (!_topPlaces)
      {
        dispatch_queue_t downloadrQueue = dispatch_queue_create("lister downloader", NULL);
        dispatch_async(downloadrQueue, ^{
            _topPlaces = [FlickrFetcher topPlaces];


            NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"_content" ascending:YES];

            NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
            NSArray *flickrTopPlacesAlphabetic = [_topPlaces sortedArrayUsingDescriptors:sortDescriptors];

            _topPlaces = flickrTopPlacesAlphabetic;
            dispatch_async(dispatch_get_main_queue(), ^{
                [your_table_view_object reloadData];
            });
        });
        dispatch_release(downloadrQueue);
      }
}

要完成他的建议,您将创建一个类型为dispatch_queue_t的实例变量,并从此函数中删除调度队列的创建和释放。有关此更具体的帮助,我们需要查看整个类的实现。