tableView在iOS开发过程中是使用最为频繁的一个基础控件,基本上所有的列表页都会用tableView,使用起来非常简单。但当数据源或者cell的布局十分复杂,tableView多少会出现卡顿的现象,十分影响用户体验。
接下来主要介绍一下,我个人在开发遇到的一些问题,以及做UITableView的性能优化时,应该注意到的几点
关于cell的高度(collectionViewCell的size)计算
1.对于一般的布局相对简单的cell来说,直接通过一下来实现即可:
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
2.对于相对复杂的cell布局来说,cell高度非固定,需要自适应高度的cell来说,高度的计算就显得很重要,因为tableView在不停地滚动时,会一直调用上面的方法,如果计算高度方法比较耗时的话,自然会影响tableView的滑动流畅度;介绍一个第三方UITableView分类FDTemplateLayoutCell,主要自动帮你计算cell高度,并且做了缓存,但是暂不支持UICollectionViewCell的自动高度计算。
小结:当需要自动计算高度时,在TableView中使用FDTemplateLayoutCell是个不错的选择,但在collectionView需要自己计算,很重要的一点是:如果cell高度或者size计算相对复杂,尽量不要在滚动时计算cell高度或者size,应该在reloadData之前计算好全部cell高度或者对cell高度做缓存。
Core Animation
这是instrument里面的测试工具,非常好用,可以测试app的性能,一般使用真机测试。
打开xcode,command + I打开Instrument,选中Core animation,如下画面:
当开始测试app时可以看到如下图的帧率变化:
这是快速滑动tableView时,屏幕的帧率变化,当帧率越接近60时,表示滑动越流畅;至于原因我这里不做细讲。
然后看右侧栏的几个选项,我会挑几个比较重要的说一下,也就是对滑动性能影响比较大的讲一下;
1) Color Blended Layers
Instruments可以在物理机上显示出被混合的图层Blended Layer(用红色标注),Blended Layer是因为这些Layer是透明的(Transparent),系统在渲染这些view时需要将该view和下层view混合(Blend)后才能计算出该像素点的实际颜色,如果这种blended layer很多,那么在滚动列表时就甭想有流畅的效果。
解决blended layer问题也很简单,检查红色区域view的opaque属性,记得设置成NO;检查backgroundColor属性是不是[UIColor clearColor],要知道背景颜色为clear color那可是图形性能的大敌,基本意味着blended layer是跑不了的了,为什么?自己思考一下:)
总之,红色区域越少肯定是越好的。
2) Color Hits Green and Misses Red
很多视图Layer由于Shadow、Mask和Gradient等原因渲染很高,因此UIKit提供了API用于缓存这些Layer:[layer setShouldRasterize:YES],系统会将这些Layer缓存成Bitmap位图供渲染使用,如果失效时便丢弃这些Bitmap重新生成。图层Rasterization栅格化好处是对刷新率影响较小,坏处是删格化处理后的Bitmap缓存需要占用内存,而且当图层需要缩放时,要对删格化后的Bitmap做额外计算。 使用这个选项后时,如果Rasterized的Layer失效,便会标注为红色,如果有效标注为绿色。当测试的应用频繁闪现出红色标注图层时,表明对图层做的Rasterization作用不大。
3) Color Misaligned Images
Misaligned Image表示要绘制的点无法直接映射到频幕上的像素点,此时系统需要对相邻的像素点做anti-aliasing反锯齿计算,增加了图形负担,通常这种问题出在对某些View的Frame重新计算和设置时产生的。
上图中被标注为黄色的图层,这是由于图层显示的是被缩放后的图片,如果这些图片是通过网络下载的,可以通过程序更新为确定的绘制大小来解决。还有些系统Navigation Bar和Tool Bar的背景图片使用的是拉伸(Streched)图片,也会被表示为黄色,这是属于正常情况,通常无需修改。这种问题一般对性能影响不大,而是可能会在边缘处虚化。
(4) Color Offscreen-Rendered Yellow
Offscreen-Rendering离屏渲染意思是iOS要显示一个视图时,需要先在后台用CPU计算出视图的Bitmap,再交给GPU做Onscreen-Rendering显示在屏幕上,因为显示一个视图需要两次计算,所以这种Offscreen-Rendering会导致app的图形性能下降。
大部分Offscreen-Rendering都是和视图Layer的Shadow和Mask相关,下列情况会导致视图的Offscreen-Rendering: 1. 使用Core Graphics (CG开头的类)。 2. 使用drawRect()方法,即使为空。 3. 将CALayer的属性shouldRasterize设置为YES。 4. 使用了CALayer的setMasksToBounds(masks)和setShadow*(shadow)方法。 5. 在屏幕上直接显示文字,包括Core Text。 6. 设置UIViewGroupOpacity。
补充:
1.在使用xib时,很多时候view的opaque属性默认为YES,需要手动设置为NO,如果view为透明可以通过设置透明背景色。
2.view的背景色尽量使用非透明,使用xib时,默认为透明,需手动设置。
3.cell的赋值方法里,尽量只做控件赋值或显示隐藏操作,不做复杂的数据计算和逻辑操作。