“UITableView完美平滑滚动”阅读笔记

来源:互联网 发布:盐城大数据产业园 编辑:程序博客网 时间:2024/05/18 03:56

一、通过内置工具实现浅层次优化

使用内置工具优化 UITableViews 的正确方式

  • 重用 cell对象:对于特定的 cell类型,你应该只初始化一次
  • 不要在cellForRowAtIndexPath: 方法绑定数据,因为这时 cell还没显示,而是使用UITableViews 的委托方法tableView:willDisplayCell:forRowAtIndexPath:
  • 进一步计算 cell的高度要迅速。虽然这是工程师的日常事务,但是要想平滑滚动复杂的 cell,你要多点耐心。

下面对上面三点稍作说明:

1、重用 cell/header/footer的单个实例是优化UITableView最显著的方式,正确的做法是,你应该持有唯一的 cell/header/footer 类,且只初始化了一次,并返回给UITableView 重用该对象。由于为每个cell都执行一次,所以这些代理函数必须迅速执行,否则会出现卡顿现象。


2UITableView tableView: heightForRowAtIndexPath:委托方法会为每个 cell(即使它不显示)调用一次,所以你应当非常迅速返回当前 cell的高度,否则会出现卡顿现象。


iOS8 开始,我们可以使用自动高度计算,而无需实现上面提到的UITableViews 委托方法。要做到这一点,你可以使用AutoLayout 工具,并把行高设置为 UITableViewAutomaticDimension。更多的详细信息可以在StackOverflow网站上找到,上面有很好的解释。尽管可以使用这些工具,但我还是强烈建议你不要这么做。另外,我建议不要使用更复杂的数学运算来确定 cell的高度,而尽可能仅仅使用加、减、乘、除。AutoLayout 难道真如我所那么?也许你会感到惊讶,但这的确是事实。如果你的应用运行在所有的生命周期长的真实设备,想看到完美的平滑滚动,那么结果会是慢得令人难以置信的。而且你拥有越多的子视图,你的AutoLayout 就运行得越慢。

AutoLayout 相对低性能的原因是在 Cassowary 布局引擎下处理的。你需要要处理的的子视图布局约束越多,你花费在返回 cell UITableViews 的时间就越多。


二、平衡CPU和GPU,实现进一步优化

上面提及的几点还不足以实现真正的平滑滚动,尤其当你需要实现复杂的 cell,有着许多梯度渐变、视图、交互元素、装饰元素等更多的内容时,其平滑滚动效果更差。你给UITableViewCell 添加的视图越多,其滚动时的 FPS下降的幅度就越大,因为cell越复杂则混合渲染的视图越多,GPU会满载,造成渲染时间被拉长

让我们把注意力转移到 UIView opaque的属性上,绘图系统根据opaque属性确定UIView 是否为透明,如果不透明,则绘图系统在呈现该视图时会做一些优化并提高性能。

GPU(图形处理器),它是显卡的心脏,与CPU类似,只不过GPU是专为执行复杂的数学和几何计算而设计的,这些计算是图形渲染所必需的。用途是将计算机系统所需要的显示信息进行转换,控制显示器的正确显示,是连接显示器和个人电脑主板的重要元件。显卡作为电脑主机里的一个重要组成部分,承担输出显示图形的任务,对于从事专业图形设计的人来说显卡非常重要。iOS系统对图形的各种特效处理基本上正好都是基于GPU硬件进行加速的,它可以不用完全借助CPU或者程序本身,而是通过GPU进行渲染以达到更流畅的操控表现,但是过多的混合渲染会使的gpu处于满载状态而造成性能下降!所以tableview中提高性能的方法是减少混合渲染,确认哪些视图进行混合渲染了的方法是:在 iOS 模拟器运行你的应用,点击“Debug”菜单,然后选择“Color Blended Layers”选项。这时 iOS模拟器会将所有区域的显示划分成两种颜色:绿色和红色,绿色区域是没有混合渲染的,红色区域是经过有混合渲染的

每次遇到这样的情况,你都应当仔细研究,并在不同的情况下,使用不同的方式来避免混合渲染,我在这种情况下,将背景色 设置不透明就已经实现目标了

但有时候我们会遇到更复杂的事情。看这里:我们有一个梯度渐变,但混合是不存在的。如果你想使用CAGradientLayer 来实现这个效果,你会失望的,因为在 iPhone 6 FPS 会下降到 25~30,并且无法达到快速滚动。

它毕竟是会发生的,因为我们已经将两个不同图层的内容混合了,分别是UILabel CATextLayer CAGradientLayer

当正确使用 CPU GPU资源,它们是负载均衡的,FPS保持约为 60。如下所示:


当设备需要显示执行大量的混合操作时问题就会出现,GPU将会满载,但 CPU 却会保持低负荷运行

通过本文的所有建议,你将能够让你的应用即使在这种情况下都可以达到 60 FPS,尽管其过程有些难度。解决方法就是:用 CPU来渲染!去载 GPU,让它只在必须用 GPU的地方执行混合渲染。例如,由CALayers 执行动画的地方。

我们可以通过在UIView drawRect: 方法中使用CoreGraphics 操作,如:

这些代码就很好吗?即使是我,也会说no。另外这种方式是撤销所有在UIView 上的缓存优化(在任何情况下,它们都是不必要的)。但正是这种做法将禁用一些混合操作,不加载 GPU并能让 UITableViews 更流畅。

但要注意:使用这种方式增加渲染性能不是因为 CPU GPU 快!而是因为 CPU 在多数情况下都不会 100%满载,这种方式能让我们通过负载 CPU来实现在一些渲染任务中去载 GPU

优化混合操作的关键是平衡 CPU GPU 的负载。

简单总结一下优化在 UITableViews 中绘制数据的操作

  • 减少 iOS没必要的混合渲染区域:通过 iOS模拟器和 Instruments 工具对应用进行检查,不使用透明背景;如果可以的话,不渲染梯度渐变,其效果会更好。
  • 优化代码,实现 CPU GPU 负载均衡。你应清晰了解哪一部分的渲染必须通过 GPU来完成,哪一部分的渲染可以通过 CPU来保持均衡。
  • 根据不同类型 cell写不同的代码。

三、通过减少子像素渲染,实现进一步优化



实际上,每个物理像素是通过红、绿、蓝三种颜色子像素组成的,这就造成了每个像素并不是原子单元的,尽管在应用中看起来是原子单元的。直到搭配视网膜屏的 iPhone 4 出现,物理像素可以被描述为整形坐标。因为视网膜显示屏是多倍于屏幕点,而不是 Cocoa Touch 环境中的像素,而且他们可以为浮点数。

理想状况下,屏幕点总是被处理成物理像素的整数坐标,但在现实生活中,它可能是浮点数值,例如,直线可能开始于横坐标的 0.25处。并从这时,iOS 对子像素进行着色。当这种技术运用于特定类型的内容(如文本)确实比较合理。但如果我们只是绘制设计的平滑直线时就没必要使用这种技术。如果你的所有的平滑直线都进行子像素渲染(这将是不可见的,因为你的直线只是设计成平滑的),那么你会让 iOS 做无用功,同时也降低了 FPS

如何获得与不必要的子像素抗锯齿的问题?最经常发生的情况是在需要代码计算的视图中,其坐标系数值变成了浮点数值或者使用不适合的图片素材,图片尺寸不对齐屏幕的物理像素(例如,你有一张 60×61而不是 60×60 的图片给视网膜屏显示)

就如前面内容提到的,在减少一些东西前,我们应去找到它。在 iOS模拟器运行你的应用,并点选“Debug”菜单的“Color Misaligned Images”选项。

这次,模拟器上有两大高亮的区域:紫红色区域执行了子像素渲染,黄色区域渲染的图片尺寸没有对齐到它们所在的区域。





如何在你的代码中找到发生问题的地方?我总是使用部分自定义绘制进行手工布局的,所以对我来说没问题。如果你是使用Interface Builder,那么我只能同情你了。

一般情况下,解决这个问题只需要简单使用下ceilffloorf CGRectIntegral 来凑整你的坐标系即可。

通过探索的结果,我有以下几点建议:

  • 凑整所有像素相关的数据:UIView的点坐标、宽高和其他数据。
  • 追踪你的图像资源:图片必须是像素完美的,否则当它们在视网膜屏上渲染时,它会做一些无必要的抗锯齿处理。
  • 定期检查你的环境和上述的问题,因为它可以很快修正。

四、通过“异步加载UI”实现进一步优化


每个中等以上级别的应用都有必要使用带自定义多媒体内容的 cell,如:文本、图片、动画,甚至有时是视频。而所有这些东西都被修饰:头像是圆的、文字带话题标签、用户名等。我们注意到,对于需要尽快返回的 cell,在这点上我们有些麻烦:clipsToBounds 慢,图片从网络加载,字符串要关联话题标签等其他一些麻烦。

优化似乎是这样的:你执行这些操作,但如果你执行在主线程,那么它不会让你快速返回 cell。后台加载图片并处理圆角,然后将处理过的图片赋值给UIImageView。一次显示所有文本,但在后台关联话题标签,然后刷新带样式的文本。

具体的操作取决于你的 cell 的具体内容,但主要的想法是让它在非主线程运行大量的操作。这些操作不仅是网络相关代码并且使用Instruments 工具来找出所在需要在代码运行的操作。


有时候,我们即使用尽了上面所有的技术都无补于事。GPU仍然不奏效(iPhone 4 + iOS 7),cell中有大量内容,我们将要通过CALayers 来实现动画,因为它真的很难通过drawRect: 方法实现效果。在这种情况下,我们应该在后台渲染其他的一切。

设置 CALayers 为异步显示模式(即使它们简单的文本或图片),也将帮助你提高 FPS,即设置CALayers drawsAsynchronously YES

iOS 模拟器运行应用,选择“Debug”菜单的“Color Offscreen-Rendered”选项。现在所有在后台渲染的区域会以黄色突出显示


如果对一些层启用该模式,但它并没有高亮突出显示,那么这个地方是还不够慢。

为了找到CALayers 的瓶颈并进一步缩小它,你可以使用 XCode Instruments Time Profiler工具。

下面是实现异步 UI 的操作列表:

  • 找到那个不能让你快速返回 cell的渲染瓶颈。
  • 将操作移至后台并更新在主线程的显示内容。
  • 最后一招是设置CALayers 为异步显示模式(即使它们简单的文本或图片),这将帮助你提高 FPS




1 0
原创粉丝点击