向UITableView快速插入行会导致NSInternalInconsistencyException

我有一个UITableView,有时有快速插入新行。 新行的插入由通知观察器处理,通知观察者监听基础数据更改时触发的更新通知。 我使用@synchronized块围绕所有的数据模型的变化和实际的通知邮件本身…希望每个增量数据更改(和行插入)将分开处理。 不过,有时候这还是失败了。 这个例外会告诉我,它预计10行(基于数据模型的计数),它以前有8行,但更新通知只告诉它插入一行(因为这是两个快速发射的通知中的第一个)。

我想了解其他人如何倾向于处理这些types的情况。 其他开发人员如何缓解两个表视图更新操作之间存在multithreading争用条件的问题? 我应该有一个更安全的锁控制更新通知(为什么不是@synchronized做它应该)?

任何意见是极大的赞赏! 谢谢。

一些伪代码:

我的模型类有一个像这样的方法,被其他线程调用来追加新的行到表视图:

- (void)addRow:(NSString *)data { @synchronized(self.arrayOfData) { NSInteger nextIndex = self.arrayData.count; [self.arrayData addObject:data]; [NSNotificationCenter.defaultCenter postNotificationName:kDataUpdatedNotification object:self userInfo:@{@"insert": @[[NSIndexPath indexPathForRow:nextIndex inSection:0]]}]; } } 

我的控制器类有这样的方法来接受kDataUpdatedNotification通知,并实际执行行插入:

 - (void)onDataUpdatedNotification:(NSNotification *)notification { NSDictionary *changes = notification.userInfo; [self.tableView insertRowsAtIndexPaths:changes[@"insert"] withRowAnimation:UITableViewRowAnimationBottom]; } 

如果您使用主队列asynchronous更改数据模型,您将遇到此问题,因为您的表视图委托方法正在查看数据模型的当前状态,这可能超出了您向表中报告的插入视图。

UPDATE

一种解决scheme是将你的更新排队到一个私有队列上,让这个队列在主队列上同步更新你的数据模型(我还没有testing过这个代码):

 @interface MyModelClass () @property (strong, nonatomic) dispatch_queue_t myDispatchQueue; @end @implementation MyModelClass - (dispatch_queue_t)myDispatchQueue { if (_myDispatchQueue == nil) { _myDispatchQueue = dispatch_queue_create("myDispatchQueue", NULL); } return _myDispatchQueue; } - (void)addRow:(NSString *)data { dispatch_async(self.myDispatchQueue, ^{ dispatch_sync(dispatch_get_main_queue(), ^{ NSInteger nextIndex = self.arrayData.count; [self.arrayData addObject:data]; [NSNotificationCenter.defaultCenter postNotificationName:kDataUpdatedNotification object:self userInfo:@{@"insert": @[[NSIndexPath indexPathForRow:nextIndex inSection:0]]}]; }); }); } 

您需要中间调度队列的原因如下。 在原来的解决scheme(如下)中,主队列上有一系列块,如下所示:

  1. 添加N行
  2. 添加第N + 1行
  3. 由N行animation的表视图张贴的块
  4. 通过表格视图为第N + 1行animation发布的块

在步骤(3)中,animation块与表视图不同步,因为(2)首先发生,导致exception(断言失败,我认为)。 因此,通过从私有调度队列中同步发布添加行块到主队列中,您可以得到如下内容:

  1. 添加N行
  2. 由N行animation的表视图张贴的块
  3. 添加第N + 1行
  4. 通过表格视图为第N + 1行animation发布的块

而不会阻碍你的工人队列。

ORIGINAL解决scheme仍然存在重叠animation的问题。

我想如果你在主队列上更新你的数据模型你会没问题的:

 - (void)addRow:(NSString *)data { dispatch_async(dispatch_get_main_queue(), ^{ NSInteger nextIndex = self.arrayData.count; [self.arrayData addObject:data]; [NSNotificationCenter.defaultCenter postNotificationName:kDataUpdatedNotification object:self userInfo:@{@"insert": @[[NSIndexPath indexPathForRow:nextIndex inSection:0]]}]; }); }