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

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

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

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

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

2、UITableView 的 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 模拟器会将所有区域的显示划分成两种颜色:绿色和红色,绿色区域是没有混合渲染的,红色区域是经过有混合渲染的。

ios uitableview 滚动到指定cell uitableview横向滚动_数据

ios uitableview 滚动到指定cell uitableview横向滚动_iOS_02

背景色 设置不透明就已经实现目标了。

CAGradientLayer 来实现这个效果,你会失望的,因为在 iPhone 6 其 FPS 会下降到 25~30,并且无法达到快速滚动。

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

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

ios uitableview 滚动到指定cell uitableview横向滚动_数据_03

GPU 将会满载,但 CPU 却会保持低负荷运行。

60 FPS,尽管其过程有些难度。解决方法就是:用 CPU 来渲染!去载 GPU,让它只在必须用 GPU 的地方执行混合渲染。例如,由 CALayers 执行动画的地方。

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

ios uitableview 滚动到指定cell uitableview横向滚动_浮点数_04

UIView 上的缓存优化(在任何情况下,它们都是不必要的)。但正是这种做法将禁用一些混合操作,不加载 GPU 并能让 UITableViews 更流畅。

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

优化混合操作的关键是平衡 CPU 和 GPU

UITableViews 中绘制数据的操作:

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

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

ios uitableview 滚动到指定cell uitableview横向滚动_数据_05

 iPhone 4 出现,物理像素可以被描述为整形坐标。因为视网膜显示屏是多倍于屏幕点,而不是 Cocoa Touch 环境中的像素,而且他们可以为浮点数。

0.25 处。并从这时,iOS 将对子像素进行着色。当这种技术运用于特定类型的内容(如文本)确实比较合理。但如果我们只是绘制设计的平滑直线时就没必要使用这种技术。如果你的所有的平滑直线都进行子像素渲染(这将是不可见的,因为你的直线只是设计成平滑的),那么你会让 iOS 做无用功,同时也降低了 FPS。

60×61 而不是 60×60

iOS 模拟器运行你的应用,并点选“Debug”菜单的“Color Misaligned Images”选项。

紫红色区域执行了子像素渲染,黄色区域渲染的图片尺寸没有对齐到它们所在的区域。

ios uitableview 滚动到指定cell uitableview横向滚动_iOS_06

ios uitableview 滚动到指定cell uitableview横向滚动_iOS_07

Interface Builder,那么我只能同情你了。

ceilf、floorf 和 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”选项。现在所有在后台渲染的区域会以黄色突出显示。

ios uitableview 滚动到指定cell uitableview横向滚动_数据_08

ios uitableview 滚动到指定cell uitableview横向滚动_iOS_09

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

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

UI

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