What is the best way to ensure a reload of a UITableView?

I have a UITableView whose dataSource is updated at random intervals in a very short amount of time. As more objects are opened, they are added to the tableView data source, and I insert a specific indexPath:

[self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; 

The data source is in the manager class, and a notification is published when it is changed.

 - (void)addObjectToDataSource:(NSObject*)object { [self.dataSource addObject:object]; [[NSNotificationCenter defaultCenter] postNotification:@"dataSourceUpdate" object:nil]; } 

ViewController updates the tableView when it receives this notification.

 - (void)handleDataSourceUpdate:(NSNotification*)notification { NSObject *object = notification.userInfo[@"object"]; NSIndexPath *indexPath = [self indexPathForObject:object]; [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; } 

This works great, but I noticed that in some cases the second object is detected just like the first calls endUpdates, and I get an exception request. I have two objects in my data source when the tableView was expecting it.

I was wondering if anyone could figure out the best way to atomize row inserts into a tableView. I was thinking of placing the @synchronized block (self.tableView) around the update, but I would like to avoid this if possible, because it is expensive.

+4
source share
1 answer

The recommended method is to create a private queue for synchronously sending batch updates to the main queue (where addRow is the method that inserts an element into the data model at the specified indexPath):

 @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 atIndexPath:(NSIndexPath *)indexPath { dispatch_async(self.myDispatchQueue, ^{ dispatch_sync(dispatch_get_main_queue(), ^{ //update the data model here [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; }); }); } 

This way you are not blocking any other threads, and the block approach ensures that the table view animation blocks (those that throw exceptions) are executed in the correct order. A more detailed explanation in Inserting a quick row in a UITableView raises an NSInternalInconsistencyException .

+3
source

Source: https://habr.com/ru/post/1495774/


All Articles