You will have this problem if you change your data model asynchronously with the main queue, because the delegate methods in the table view look at the current state of the data model, which may be ahead of the inserts you attach to the table view.
UPDATE
One solution is to queue your updates in the private queue, and this queue updates your data model in the main queue synchronously (I have not tested this code):
@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]]}]; }); }); }
The reason you need an intermediate send queue is as follows. In the original solution (below), you get a series of blocks in the main queue that look something like this:
- Add line N
- Add line N + 1
- A block placed as a table for animating row N
- A block placed as a table for animating N + 1 strings
In step (3), the animation block is not synchronized with the table view because (2) happened first, which leads to an exception (for example, a statement fails). Thus, sending the block to add rows to the main queue synchronously from the private send queue, you get something like the following:
- Add line N
- A block placed as a table for animating row N
- Add line N + 1
- A block placed as a table for animating N + 1 strings
without delaying work queues.
ORIGINAL The solution still has problems with overlapping animations.
I think that everything will be fine if you update the data model in the main queue:
- (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]]}]; }); }
source share