iOS问题记录本:UITableView点击Cell的同时刷新数据导致闪退

0.背景描述

项目中有一个功能显示列表数据,列表上有搜索框用来筛选列表中的数据。
两个月前上线后发现友盟错误统计中出现少量的空数组取数闪退。

1.问题查找

因为闪退是在UITableView的didSelectRow代码方法中产生的,但是我的业务代码在从数据array里取数前做了边界判断:

if (indexPath.row<=self.dataArray.count-1) {
    NSDictionary *dict = self.dataArray[indexPath.row];
}

但实际上,在取数时还是闪退了。
因为本功能相当简单常见,所以将怀疑的目光投向了搜索功能;甚至我一度怀疑是不是在搜索框输入时,因为会有键盘弹出,所以在某些机型上,键盘会导致闪退。
所幸,后来在同事的手机上重现了该问题,随后通过不断的实验,做到了必现该问题。操作步骤如下:
进入界面->点击搜索框弹出键盘,保证是中文输入法->点击输入,因为输入的字符还是中文备选状态,所以此时搜索框的didChange代码方法并未触发->然后直接点击列表中的cell->这时候代码进入UITableView的didSelectRow方法,而我在此方法中首先隐藏键盘,然后再处理我自己的业务逻辑。
而问题就出现这里:因为我首先隐藏键盘,键盘被隐藏后,随即触发了搜索框的didChange事件,而该事件中我对列表数据进行筛选后,修改列表数据数组,随后reloadData。但是因为以上步骤都是同步操作,所以再执行完以上步骤后,又开始执行didSelectRow方法中的剩余代码,而此时dataArray已经变成了空。
那么问题就来了,在dataArray的count为0,indexPath为0-0的情况下indexPath.row<=self.dataArray.count-1该句表达式的结果竟然是true,从而进入了下面的取数据代码,造成闪退。

2.问题原因

通过以上的分析,我知道在以上的情况下,系统认为0<=0-1是成立的。
所以我不得不怀疑indexPath.row本身的类型有问题,所以导致它和-1进行比较时永远为true。
随后我将indexPath.row进行强制类型转换,又转换成NSNumber再转换回来,可都无法解决该问题。
到了后面我甚至去怀疑indexPath.row<=self.dataArray.count-1表达式中<=-两个操作符的优先级问题……
最后我将表达式改成indexPath.row+1<=self.dataArray.count,终于系统返回为false。
因此我怀疑在UITableView的didSelectRow事件中刷新UITableView导致其所持有的NSIndexPath对象出现问题,从而indexPath.row不再是普通的NSInteger类型的值。而这一值进行+1运算后,又变成了普通的数值,所以比对结果正常了。

3.解决方法

3.1 治本

该问题的根本在UITableView传出的indexPath对象出现问题。所以需要将该问题提交给苹果,由他们审查并处理。但这却无法马上解决我们的问题。

3.2 治标

  1. 不要在UITableView的代码方法在触发UITableView的刷新方法。
  2. 不要直接使用indexPath.row和其他数值做大小判断。
  3. 如果第一点无法完全避免,那么就要保证不在indexPath.row和其他数值判断之前触发UITableView的刷新方法。在我的代码中,就比如在didSelectRow方法的最后再去隐藏键盘。

猜你喜欢

转载自blog.csdn.net/jhq1990/article/details/80516793
今日推荐