看装B

小心UITableView中的"数组越界Crash&q

2017-01-11  本文已影响482人  南华coder

使用UITableView的reloadData时候,有时候会遇到数据越界的Crash,其根源在于:

使用reloadData刷新UITableView时候,UITableViewDataSource和UITableViewDelegate的回调方法中,有些是同步发生的,有些则是异步发生的(如:cellForRowAtIndexPath是异步执行的)。

例1:同步的回调:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 
  return self.dataSource.count;
}

例2:异步的回调:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath )indexPath{
//... NSString
content = self.dataSource[indexPath.row];
//...
}

总结:如果在异步执行cellForRowAtIndexPath时候,self.dataSource发生了变化(如删除某一个元素),极有可能发生数组越界的异常。因为reloadData返回之后,下一次loop就开始执行异步的操作了。在多线程场景下,列表界面的数据有可能经常变化,就可能会出现偶现的bug了;当列表界面数据不怎么变化的时候,几乎感知不到这种异常的存在。

目前的处理办法是:因为dataSource类型是NSMutableArray,为NSMutableArray提供一个safeObjectAtIndex方法,这个方法放到NSMutableArray的分类中。

static NSString * const kCellReuseIdentifier = @"kCellReuseIdentifier";
// ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellReuseIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellReuseIdentifier];
    }

    NSString *content = [self.dataSource safeObjectAtIndex:indexPath.row];
    cell.textLabel.text = content;
    cell.backgroundColor = [UIColor redColor];
    return cell;
}

NSMutableArray的safeObjectAtIndex声明和实现如下

//NSMutableArray+Safe.h
@interface NSMutableArray (Safe)
- (id)safeObjectAtIndex:(NSUInteger)index;
@end

//NSMutableArray+Safe.m
#import "NSMutableArray+Safe.h"
@implementation NSMutableArray (Safe)

- (id)safeObjectAtIndex:(NSUInteger)index{

    if (index < self.count){
        return [self objectAtIndex:index];
    }else{
        NSLog(@"警告:数组越界!!!");
    }
    return nil;
}

小尾巴:我们为什么不使用runtime的特性,混写NSMutableArray的objectAtIndex

参考链接:危险的UITableView

上一篇下一篇

猜你喜欢

热点阅读