| 
 更新提示:  
【2018年11月20日更新】  
经过放置在项目中运行发现,如果在快速滚动tableview的时候会在下面这行代码中崩溃(慢慢的滚动是没关系的~):  
 
 CGFloat cellHeight = [tableView rectForRowAtIndexPath:[NSIndexPath
indexPathForRow:(indexPath.row - 1) inSection:indexPath.section]].size.height;  
  
提示的error原因是,超出数组的范围进行访问。原因,后面有时间会详细说明更新进来,大致的原因就是利用rectForRowIndexPath方法去取cell的时候,从展示在界面上的第一个完整的cell开始作为下标为0的cell。比如,一个界面中可以存放4个cell,第5个cell将要展示的时候,会在界面中去取下标为3的cell。有一点需要插播一条,就是在第5个cell还没有漏出来之前,系统就会去调用tableview的cellForRowAtIndexPath协议方法了,这就是为什么你慢慢的滚动tableview是没有关系的。如果快速滚动的话,虽然系统也是在第5个cell还没有漏出来之前就去调用那个协议方法了,但是等到运行到rectForRowIndexPath方法的时候,第1个cell就已经被顶出tableview的可视区域了,这个时候下标为0的cell就是从开始的第2个cell开始了(第一个cell在屏幕中的部分并不是完整的了),所以就会抛出异常。  
暂时先把“indexPath.row - 1”的“-1”改为“-2”暂且应付。  
因为如果tableview的可视范围最多只能同时容纳2个完整的cell的话,使用“-2”就会往前超域访问数组;如果最多只能同时容纳1个完整的cell的话,使用“-1”也会往前超域访问数组;如果连一个完整的cell都容纳不下,那么这个方法就根本行不通了。(很尴尬~)  
  
   
问题背景: 
使用MJRefresh一直都很方便,适配到iOS11以后,tableView上拉加载更多数据动画结束后,出现tableView跳动、闪动的现象。  
通过浏览Github上的MJRefresh的Issues后发现,很多人都遇到了这个问题。而且,一般遇到这个问题的都是使用自动化布局来自动约束Cell高度的同学。如果将Cell是通过tableView的rowHeight属性或者对应的协议方法给定的,就不出遇上这个问题。  
         
   
分析问题: 
为了实现Cell的高度自适应,需要做三步:  
1、不要设置rowHeight、不要重写设置rowHeight的协议方法  
2、在搭建Cell的UI时,让最后一个控件的bottom等于cell.contentView.mas_bottom(这里用masonry举例)  
3、设置tableView的下面两个属性:  
 
 self.estimatedRowHeight = 44;
self.rowHeight = UITableViewAutomaticDimension;  
  
有同学说,走回以前“根据内容计算好cell的高度”的方式,很定是不合适的,与苹果推崇的AutoLayout相违背。  
所以使用上面的高度自适应方式,是没错的,错就错在  
estimatedRowHeight  
这个属性的设置。  
如果通过高度自适应计算出来Cell的真实高度与给出的估算高度相差太大,很定出现view渲染过程的异常。  
解决方式: 
根据上面的分析,本ID采用的方式是加载cell时,将上一个cell对象的高度设置为下一个即将出现的cell的预估高度。  
 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath { 
    if (indexPath.row > 1) {
        CGFloat cellHeight = [tableView rectForRowAtIndexPath:[NSIndexPath
indexPathForRow:(indexPath.row - 1) inSection:indexPath.section]].size.height;
        self.estimatedRowHeight = cellHeight;
    }
    
    //。。。你之前的代码  
    return cell;
} 
  
   |