背景
最近做了个需求,UITableView用了beginUpdates/endUpdates来刷新单个cell,但是发现左滑删除数据时会出现数组越界的崩溃,模拟代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block NSIndexPath *index = indexPath;
__weak __typeof(&*self)weakSelf = self;
cell.deleteBlock = ^(void) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof(&*weakSelf)self = weakSelf;
NSIndexPath *path = [NSIndexPath indexPathForRow:index inSection:0];
[self.dataSource removeObject:obj];
[self.tableview beginUpdates];
[self.tableview deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft];
[self.tableview endUpdates];
});
};
}
原因
经过定位问题,最终发现是beginUpdates/endUpdates的问题,用这个方法做刷新是比直接reloadData在性能上更好,因为reloadData是刷新整个tableview的,而beginUpdates/endUpdates只会更新单个cell,但是在删除代码时,因为只更新了单个cell,其他cell不会改变,其对应的index也不会因为删除了cell而变更,导致删除更大的行数时超出了数据源的个数而出现数组越界了。
解决
因为不想reloadData刷新整个tableview,最后用改成用选中的cell对应的obj去数据源寻找真正的index。 模拟代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *index = indexPath;
__block NSString *obj = [self.dataSource objectAtIndex:index];
cell.obj = obj;
__weak __typeof(&*self)weakSelf = self;
cell.deleteBlock = ^(NSString * _Nonnull obj) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof(&*weakSelf)self = weakSelf;
NSInteger index = [self.dataSource indexOfObject:obj];
if (index != NSNotFound) {
NSIndexPath *path = [NSIndexPath indexPathForRow:index inSection:0];
[self.dataSource removeObject:obj];
[self.tableview beginUpdates];
[self.tableview deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft];
[self.tableview endUpdates];
}
});
};
}