UITableViewDataSource异步加载

问题描述:

我有一个UITableView,这应该使条目分为部分。 数据需要处理一定的时间,因此它的工作是这样的:UITableViewDataSource异步加载

@interface AsyncTable() 
    NSMutableArray* _alphaKeys; 
@end 

@implementation AsyncTable   
-(void)refreshData { 
     dispatch_async(_serialQueue, ^{ 
      <load of the _alphaKeys> 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [table reloadData]; 
      }); 
     }); 
} 
... 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return [_alphaKeys count]; 
} 
... 
@end 

现在,这个完美的作品首次。

但我的数据有时会改变,我从通知调用方法refreshData。 并且它正在开始崩溃,例如在执行numberOfSectionsInTableView,并在cellForRowAtIndexPath时间的阵列可以具有不同的内容的引用。

问题是时机,让我们假设有2级呼叫的每相继到来短: 第一个是加载完成并在主线程调度reloadData,然后第二个请求是与数据的重载启动主线程调用之前...

任何建议如何解决这个问题?我不想把所有东西都放在主线程中(它可以工作,我现在试图重构应用程序以使它更具响应性)

+1

'reloadData' SUD没有在后台被调用,它的错误的方式重新加载'tableView' – Mukesh

+0

@muku'reloadData'不是从后台调用,这是调用主线程(请参阅上面的代码)。或者我错过了这一点?我想在后台处理完成后调用reload –

+1

嗨。 1)第一种方法是用'NSOperation'重构代码。这是允许您取消以前的操作。 2)第二种方法是添加一个追加加载状态的变量。在调用'[table reloadData]'之前,你需要检查这个变量。 –

您的问题是由于更新数据源(_alphaKeys)与tableView loading 。 UITableView异步加载,无法分辨何时完成。但是,如果更改数据源并立即调用reloadData,即使正在进行加载,它也会做正确的事情。诀窍是数据的改变必须在主线程上完成。

我对您的回答是更改您的代码,以便后台线程在一份数据上进行处理。当处理完成后,主线程新的数据复制到表视图的数据源,然后立即打电话reloadData上运行的模块。

见我修改您的示例代码:

@interface AsyncTable() 
    NSArray* _alphaKeys; // <-- copy for data source is immutable 
@end 

@implementation AsyncTable   
-(void)refreshData { 
     dispatch_async(_serialQueue, ^{ 
      NSMutableArray *alphaKeysCopy = [_alphaKeys mutableCopy]; // <-- Create a new array if processing does not require current state 
      <load of the alphaKeysCopy> 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       _alphaKeys = [alphaKeysCopy copy]; // <-- Copy on the main thread so the table view can't see an intermediate state 
       [table reloadData]; 
      }); 
     }); 
} 
+0

谢谢!这是个好主意。另外一个问题是:'但是,如果更改数据源并立即调用reloadData,即使加载正在进行,它也会做正确的事情 - 您从哪里得到它?上面的@Mozilla提示起作用,但我不是100%肯定的,就像我不知道如何实现'reloadData'一样。如果这只是一堆异步调用来获取行数,在不同的块中绘制每一个raw等等,我的代码的第二次调用会在主要队列中的这些调用之间插入另一个_alphaKeys副本。你不这么认为? –

+1

表视图(重新)加载是一个实现细节,但我的实验显示'reloadData'设置状态并触发该过程。在连续的循环中,调用数据源方法(numberOfRowsInSection,numberOfSections,cellForRowAtIndexPath等)来构建表。如果您在第一次调用之后在runloop迭代中调用'reloadData',则该表只会重置并重新开始。 – Avi