UITableViewDataSource异步加载

时间:2015-11-06 11:14:45

标签: ios objective-c multithreading uitableview

我有UITableView,应该将条目分为部分。 数据需要一些时间处理,因此它是这样做的:

@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时,数组可能会引用不同的内容。

问题出在时间上,让我们假设有两个电话紧随其后: 第一个是在主线程中完成加载和调度reloadData,然后第二个请求到来,并在调用主线程之前重新加载数据...

任何建议如何解决这个问题?我不想把所有内容放在主线程中(它可以工作,我现在正在尝试重构应用程序以使其更具反应性)

1 个答案:

答案 0 :(得分:1)

您的问题是由与tableView加载同时更新数据源(_alphaKeys)引起的。 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];
            });
        });
}