在iOS应用中,UITableView应该是使用率最高的视图之一了。iPod、时钟、日历、备忘录、Mail、天气、照片、电话、短信、Safari、App Store、iTunes、Game Center几乎所有自带的应用中都能看到它的身影,可见它的重要性。
然而在使用第三方应用时,却经常遇到性能上的问题,普遍表现在滚动时比较卡,特别是table cell中包含图片的情况时。
实际上只要针对性地优化一下,这种问题就不会有了。有兴趣的可以看看LazyTableImages这个官方的例子程序,虽然也要从网上下载图片并显示,但滚动时丝毫不卡。
下面就说说我对UITableView的了解。不过由于我也是初学者,或许会说错或遗漏一些,因此仅供参考。

首先说下UITableView的原理。有兴趣的可以看看《About Table Views in iOS-Based Applications》。
UITableView是UIScrollView的子类,因此它可以自动响应滚动事件(一般为上下滚动)。
它内部包含0到多个UITableViewCell对象,每个table cell展示各自的内容。当新cell需要被显示时,就会调用tableView:cellForRowAtIndexPath:方法来获取或创建一个cell;而不可视时,它又会被释放。由此可见,同一时间其实只需要存在一屏幕的cell对象即可,不需要为每一行创建一个cell。
此外,UITableView还可以分为多个sections,每个区段都可以有自己的head、foot和cells。而在定位一个cell时,就需要2个字段了:在哪个section,以及在这个section的第几行。这在iOS SDK中是用NSIndexPath来表述的,UIKit为其添加了indexPathForRow:inSection:这个创建方法。
其他诸如编辑之类的就不提了,因为和本文无关。

介绍完原理,接下来就开始优化吧。

  1. 使用不透明视图。
    不透明的视图可以极大地提高渲染的速度。因此如非必要,可以将table cell及其子视图的opaque属性设为YES(默认值)。
    其中的特例包括背景色,它的alpha值应该为1(例如不要使用clearColor);图像的alpha值也应该为1,或者在画图时设为不透明。

  2. 不要重复创建不必要的table cell。
    前面说了,UITableView只需要一屏幕的UITableViewCell对象即可。因此在cell不可见时,可以将其缓存起来,而在需要时继续使用它即可。
    而UITableView也提供了这种机制,只需要简单地设置一个identifier即可:

    static NSString *CellIdentifier = @"xxx";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {   cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];}

    值得一提的是,cell被重用时,它内部绘制的内容并不会被自动清除,因此你可能需要调用setNeedsDisplayInRect:或setNeedsDisplay方法。
    此外,在添加table cell的时候,如果不需要动画效果,最好不要使用insertRowsAtIndexPaths:withRowAnimation:方法,而是直接调用reloadData方法。因为前者会对所有indexPaths调用tableView:cellForRowAtIndexPath:方法,即便该cell并不需要显示(不知道是不是bug),这就可能创建大量多余的cell。勘误:只是在模拟器上测试如此,真机调试时没有这种bug。

  3. 减少视图的数目。
    UITableViewCell包含了textLabel、detailTextLabel和p_w_picpathView等view,而你还可以自定义一些视图放在它的contentView里。然而view是很大的对象,创建它会消耗较多资源,并且也影响渲染的性能。
    如果你的table cell包含图片,且数目较多,使用默认的UITableViewCell会非常影响性能。奇怪的是,使用自定义的view,而非预定义的view,明显会快些。
    当然,最佳的解决办法还是继承UITableViewCell,并在其drawRect:中自行绘制:

    - (void)drawRect:(CGRect)rect {      if (p_w_picpath) {        [p_w_picpath drawAtPoint:p_w_picpathPoint];       self.p_w_picpath = nil;  } else {      [placeHolder drawAtPoint:p_w_picpathPoint];   }   
    
        [text drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeTailTruncation];}

    不过这样一来,你会发现选中一行后,这个cell就变蓝了,其中的内容就被挡住了。最简单的方法就是将cell的selectionStyle属性设为UITableViewCellSelectionStyleNone,这样就不会被高亮了。
    此外还可以创建CALayer,将内容绘制到layer上,然后对cell的contentView.layer调用addSublayer:方法。这个例子中,layer并不会显著影响性能,但如果layer透明,或者有圆角、变形等效果,就会影响到绘制速度了。解决办法可参见后面的预渲染图像。

  4. 不要做多余的绘制工作。
    在实现drawRect:的时候,它的rect参数就是需要绘制的区域,这个区域之外的不需要进行绘制。
    例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判断是否需要绘制p_w_picpath和text,然后再调用绘制方法。

  5. 预渲染图像。
    你会发现即使做到了上述几点,当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,然后再绘制到屏幕,详细做法可见《利用预渲染加速iOS设备的图像显示》。

  6. 不要阻塞主线程。
    做到前几点后,你的table view滚动时应该足够流畅了,不过你仍可能让用户感到不爽。常见的现象就是在更新数据时,整个界面卡住不动,完全不响应用户请求。
    出现这种现象的原因就是主线程执行了耗时很长的函数或方法,在其执行完毕前,无法绘制屏幕和响应用户请求。其中最常见的就是网络请求了,它通常都需要花费数秒的时间,而你不应该让用户等待那么久。
    解决办法就是使用多线程,让子线程去执行这些函数或方法。这里面还有一个学问,当下载线程数超过2时,会显著影响主线程的性能。因此在使用ASIHTTPRequest时,可以用一个NSOperationQueue来维护下载请求,并将其maxConcurrentOperationCount设为2。而NSURLRequest则可以配合GCD来实现,或者使用NSURLConnection的setDelegateQueue:方法。
    当然,在不需要响应用户请求时,也可以增加下载线程数,以加快下载速度:

    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {    if (!decelerate) {        queue.maxConcurrentOperationCount = 5;   }}
    
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { queue.maxConcurrentOperationCount = 5;}
    
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {    queue.maxConcurrentOperationCount = 2;}

    此外,自动载入更新数据对用户来说也很友好,这减少了用户等待下载的时间。例如每次载入50条信息,那就可以在滚动到倒数第10条以内时,加载更多信息:

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {   if (count - indexPath.row < 10 && !updating) {     updating = YES;      [self update];    }}// update方法获取到结果后,设置updating为NO

    还有一点要注意的就是当图片下载完成后,如果cell是可见的,还需要更新图像:

    // 也可不遍历,直接与头尾相比较,看是否在中间即可。

    最后还是前面所说过的insertRowsAtIndexPaths:withRowAnimation:方法,插入新行需要在主线程执行,而一次插入很多行的话(例如50行),会长时间阻塞主线程。而换成reloadData方法的话,瞬间就处理完了。

转载于:https://blog.51cto.com/jeason/1728824

iOS 提高tableView 性能的优化相关推荐

  1. iOS tableView性能优化之异步排版和绘制渲染----YYText框架学习(YYTextAsyncLayer)

    YYWebImage源码分析 YYImage源码 YYModel源码解析 前言 这段时间针对设计架构,解耦以及性能优化相关的知识点看了不少,前两者可以看MVVM和AOP编程思路,最后一个是昨天看的,Y ...

  2. 优化tableView性能(针对滑动时出现卡的现象)

    优化tableView性能(针对滑动时出现卡的现象) 在iOS应用中,UITableView应该是使用率最高的视图之一了.iPod.时钟.日历.备忘录.Mail.天气.照片.电话.短信. Safari ...

  3. 提高C++性能的编程技术笔记:设计优化/可扩展性/系统体系结构相关+测试代码

    1. 设计优化 我们可以粗略地将性能优化分为两种类型:编码优化和设计优化.编码优化定义为不需要完整理解要解决的问题或者应用程序的执行流程就能实施的优化.通过定义看出,编码优化用于局部代码,同时该过程不 ...

  4. 提高C++性能的编程技术笔记:编码优化+测试代码

    缓存:在现代处理器中,缓存经常与处理器中的数据缓存和指令缓存联系在一起.缓存主要用来存储使用频繁而且代价高昂的计算结果,这样就可以避免对这些结果的重复计算.如,循环内对常量表达式求值是一种常见的低性能 ...

  5. 提高C++性能的编程技术笔记:虚函数、返回值优化+测试代码

    虚函数:在以下几个方面,虚函数可能会造成性能损失:构造函数必须初始化vptr(虚函数表):虚函数是通过指针间接调用的,所以必须先得到指向虚函数表的指针,然后再获得正确的函数偏移量:内联是在编译时决定的 ...

  6. mysql属性配置提高查询_MYSQL性能优化-安装时优化参数配置提高服务性能

    MYSQL性能优化一直是个头痛的问题,目前大多都是直接把页面html静态页面或直接使用了缓存技术,下面我就mysql本身的性能优化来分享一下. 安装时优化参数配置提高服务性能 在Linux下安装Mys ...

  7. bios调整服务器性能模式吗,优化BIOS设置提高显示性能

    优化BIOS设置提高显示性能 互联网   发布时间:2009-04-21 00:57:14   作者:佚名   我要评论 显示性能是集成主板发挥性能最主要的瓶径,尤其是在运行3D游戏等考验显卡性能的程 ...

  8. iOS App 启动性能优化

    为什么80%的码农都做不了架构师?>>>    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq. ...

  9. [iOS Animation]-CALayer 性能优化实例

    2019独角兽企业重金招聘Python工程师标准>>> 一个可用的案例 现在我们已经对Instruments中动画性能工具非常熟悉了,那么可以用它在现实中解决一些实际问题. 我们创建 ...

最新文章

  1. 中国国际消费电子博览会拥抱转型,全新面貌拭目以待!
  2. PHP即将退出,PHP4即将退出历史舞台
  3. 有了这个算法,图像上文字擦除再也用不上PS了
  4. python二维平面上依次得到(0,0)距离相等的点(x,y)坐标,并打印距离
  5. Linux查看服务器总内存和总硬盘大小
  6. 暴走漫画系列之高仿淘宝收货地址(附demo)
  7. 如何学习渗透测试:初学者教程
  8. 控制机械手叫什么_机械手控制系统?
  9. 复旦教授疯狂打车800次,发现大数据杀熟的秘密!附完整调研报告
  10. Google SRE: SLI、SLO、SLA 、Error Budget 详解
  11. 云南国税网上办税无法打印发票的解决办法
  12. 最简单的U盘安装windows系统教程
  13. 你必须要知道的软件测试3个主流方式
  14. CutefishOS 0.6 Beta 发布
  15. 解决win10内存占用逐渐变大(亲测有效)
  16. 获取门店出错(44)美团聚宝盆 门店映射报错
  17. 计算机应用应用研究,计算机应用研究属于什么期刊_计算机应用研究_计算机研究应用...
  18. python中pop什么意思
  19. 爬虫第十式:多线程爬取小米应用商店聊天社交类别
  20. linux监控应用运行情况,技术|在linux中如何通过nload来监控网络使用情况

热门文章

  1. GSM A5/1算法C语言代码实现和分析
  2. emmc linux.格式化参数,大家都是怎么格式化emmc芯片的?能在ADB SHELL 中操作吗?uboot 就实现了GPT分区和烧录功能...
  3. jpa-和-mybatis创建的事物管理器名称
  4. C++_STL——unordered_map、unordered_multimap、unordered_set、unordered_multiset
  5. android源代码居中字体,Android (布局优化) TextView实现drawable图标大小 位置与第一行文本居中...
  6. checkbox选中和不选中_我的lt;input /gt;不可能这么可爱
  7. 计算机禁用了网络怎么qtyong,如何禁用Qpushqt按钮?
  8. web 平台搭建-LAMP-源码包(CentOS-6)
  9. 华为p20可以用云闪付吗_华为hcIE有多难?零基础可以通过华为hcie认证吗?
  10. 历史有资产忘记折旧如何处理_紧急提醒! 500万以下固定资产一次性计入“管理费用”的,会计抓紧调账!...