我有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,然后第二个请求到来,并在调用主线程之前重新加载数据...
任何建议如何解决这个问题?我不想把所有内容放在主线程中(它可以工作,我现在正在尝试重构应用程序以使其更具反应性)
答案 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];
});
});
}