作为一名沉溺于文艺和逗比生活的另类程序员,写技术博客一直就不是我的爱好或者觉得该做的事。
不得不吐槽一下优快云博客的体验,当我下午3点已经完成这篇文章的80%时,点了一下保存按钮,结果神奇的发现只保存了半小时以前的工作状态,新写的东西全没有save掉。当时已经有砍人的冲动了。。。。结果还是坚持重写了一遍。
以下是正文:
今天刚好同事问了我autolayout下table view 动态高度cell的计算方式,想想还是写篇文章整理一下。之前XCode群里的不少朋友也问过这个问题,希望你们能读读我写的这篇文章,至少能够解决一些问题。(看完文章之后如果觉得有不妥或者笔误之处请留言或私信我的新浪微博@Saber | 断了弦的吉他 | iOS程序渣 我是不介意你来粉一下我的,反正粉也少的可怜)。
相信Table View这东西是每个iOS程序员再熟悉不过的东西了。不过每当iOS版本一更新的时候,总会有些更新是大家没去关注的,结果出现了各种各样的问题(致命的bug等)。
这篇文章主要就讲讲如何在iOS7 / 8下面做动态的cell高度的计算(比如微信朋友圈这种)该如何去做。由于普适性问题,还是用Obj-C去做示例了,想要swift的请自行脑补转换代码。。。。
First of all,先挖点坟,讲讲table view的动态高度计算的演变过程吧(个人code转变历程)。
计算高度的核心delegate selector就是这个方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
这个方法的作用是,在每次table view初始化的时候,会调用dataSource.count次,计算出所有cell的高度。并且,在table view滚动的时候,也进行计算调用。
这时,table view 的delegate调用顺序是:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
看到这里,你是不是也发现了一个致命的问题?没错,对于布局相对复杂的cell来说,每次计算的开销实在太大了,尤其是那个还在使用256M内存iPhone 4的时代。这样做的结果就是导致了用户在滚动table的时候出现了卡顿的现象。
开发者可以用这样的办法来solve这个问题:
1.创建一个cell height pool,目的是缓存第一次计算出来的height
2.每次在调用heightForRow的时候,先从height pool中查询是否有值,如有,直接return这个值;反之,则计算一个新的,存储到height pool中去。
3.当didReceiveMemoryWarning时,清空缓存池。
是的,这样解决了table在滚动时,由于计算开销导致滚动卡顿的问题。
然而这一切并没有什么卵用。
由于heightForRow这个方法在每次table初始化的时候,将dataSource.count个数的cell高度全部计算出来,导致当cell个数繁多时,进入页面的速度还是有明显的延时。
在iOS7的时候,苹果终于承认了table自身在动态计算高度时候的性能瓶颈,聪明的苹果工程师设计了这个方法:
- (CGFloat)tableView:(UITableView *)t