
有时,您会发现自己的应用无法正常运行。 因此,这里提供了一些您可以使用的工具以及可以使事情变得更好的最佳实践。
这是本文的第二部分,基于2017年国际移动开发者大会
MBLT DEV的 Fyusion的iOS工程师,RayWenderlich.com上的iOS开发教程作者Luke Parham的主题演讲。
核心动画乐器
如果您进行了大量分析,并且发现了所有瓶颈,那么有时仍然存在性能问题。 这是因为UI东西在iOS中的工作方式。 每当您设置框架或制作UIViews时,实际上发生在后台的都是您制作CATransaction或系统为您制作。 这些被运送到称为“渲染服务器”的东西。 渲染服务器负责制作动画。 如果您执行UIView animateWith:等等,那么所有操作都将在渲染服务器上发生,该服务器是另一个线程,它将处理应用程序的所有动画。

这是一个Time Profiler,其顶部有一个帧速率表。 底部是调试选项中最重要的部分。 我们将介绍两个最重要和最容易解决的问题。

第一个是颜色混合层。 这是一个非常容易解决的问题。 这使我们进入了表演警察的第一部分。 基本上,许多应用程序都存在问题:甚至iMessage(心爱的Apple应用程序)也做了很多不太出色的事情。 在这里,我们看到有很多红色:

红色表示您的标签带有白色背景。 然后,它们位于另一个白色背景之上,并且由于某种原因,它们未设置为不透明。 因此,搅拌器将这些颜色(白色和白色)混合在一起,从而得到白色。 对于具有红色的每个像素,它都会进行额外的计算而没有任何益处,但是背景仍然会变为白色。
为避免这种情况,只要它们在同一颜色上具有相同的颜色,就可以使它们尽可能不透明。 如果子视图具有相同的背景色,则不需要混合。 您所要做的就是将图层的不透明度设置为1,然后确保设置了背景色。 如果您的背景颜色是透明的,则它永远不会是不透明的。

屏幕外渲染
如果打开此选项,则屏幕外渲染的元素将以黄色显示。 关于Core Animation工具的好处是您可以看到其他应用程序。 您可以打开这些选项,然后转到系统中的任何应用程序,然后可以查看它们在做什么错。 在这种情况下,Instagram顶部会显示这些小气泡,向您展示人们的故事。

如您所见,它们都是黄色的。 在iPhone 5上,它们的速度非常慢。 这是因为屏幕外渲染比alpha混合差得多。 它使GPU停顿。 最终必须在GPU和CPU之间来回进行额外的计算,因此您将获得大多数情况下不必要的额外停顿。
贝塞尔曲线路径而不是视图转弯
下一条规则:不要使用转角半径属性。 如果您有一个视图并设置了view.layer.cornerRadius,则这总是引入屏幕外渲染。 相反,您可以使用贝塞尔曲线路径和早期的同类CGBitmap内容。 在这种情况下,为UIGraphics上下文。 此函数与UIImage一起使用,它具有一定的大小,并根据该大小进行圆角处理,并使用贝塞尔曲线路径进行剪切。 然后,我们裁剪图像并从UIImage上下文返回它。 因此,这将返回一个预先舍入的图像,而不是舍入该图像所在的视图。

最后一个例子。 这是Twitter,这是此动画运行的实时视图。 它应该打开并向您显示信息,但是所有这些文本和内容均已在屏幕外呈现,因此使动画变慢了爬行的速度。 这是我在App Store上的应用程序中发现的性能最低的东西。

那么这是怎么发生的呢? 导致这种情况发生的一件事是CALayer的shouldRasterize属性。 这是图层上的一个选项,允许您缓存已渲染的纹理。 有很多奇怪的规则。 就像在一定的毫秒数内未使用它一样,它将离开缓存。 然后,如果它离开缓存,它将在每帧上进行屏幕外渲染。 拥有它可能带来的好处并不值得。 而且很难检查它是否真的使您受益。
总结
如果可以,请避免屏幕外渲染和Alpha混合。 有时需要进行Alpha混合。 它比屏幕外渲染更好。 屏幕外渲染的发生有两个原因。 它可能来自阴影。 它可能发生在圆角处; 它可能是由于遮罩而发生的。
尽可能使视图不透明。 不要尽可能使用转角半径属性使用贝塞尔曲线路径。 另外,如果要进行文字阴影处理,请不要使用图层阴影属性。 您可以改用NSShadow。
活动追踪
活动跟踪是时间分析器将执行的操作的一种非常低级别的版本。 它为您提供了所有线程及其交互方式的视图。 而且非常复杂。 但是它具有可以设置的非常好的功能。
系统跟踪
使用
系统跟踪来跟踪特定事件的时间。 您可以设置跟踪特定事件和代码段的方式,并查看它们在实际应用程序中花费的时间。 它使您可以获得有关系统中发生的事情的细粒度信息。
- 使用“路标”来表示何时发生重要事件。
- 当/如果您希望看到动画或类似事件时,点是单个事件。
- 地区有起点和终点。 对于图像解码,您可以看到它的开始时间和结束时间,从而可以估计通常需要多长时间。

这是设置系统跟踪模板的方法。 您列出了可能发生的事件。 因此,第一名是图像下载。 二是图像解码,三是我添加的倾斜动画。 基本上,您设置了一些其他选项来查看将要使用的颜色。 基本上,您发送给它的数字是1或2,根据您在其中发送的内容,它将是红色或绿色。

如果您在Objective-C中,则必须导入此kdebug_signpost标头。 在Swift中,它仅对您可用。

然后,您必须调用kdebug_signpost或kdebug_signpost_start和kdebug_ signpost_end这个函数。 他们可以处理您传入的代码。 因此,我们用这些数字设置了这三个事件。 然后,您在此处传递该号码。 您向它传递一个对象,该对象基本上是此事件的关键。 然后,最后一个数字是颜色。 所以2就像你知道红色一样。
我在
GitHub上有一个Swift示例项目。 我有点简化。 有一个起点和终点比较容易处理。
一旦运行了跟踪,这就是它的样子。 起初它不会显示任何内容。 然后,当您终止该应用程序时,它将进行一些计算并在此处显示内容。

在这里,我们可以看到大约200毫秒的图像下载时间。 然后,图像解码大约需要40毫秒。 如果您的应用程序中发生了很多疯狂的事情,这真的很酷。 您可以设置所有这些事件,然后仅查看它们各自花费多长时间以及它们之间如何交互的读数。 系统跟踪就是这样。
红利
看一下相机减速的示例,在该示例中,我们可以看到如果应用中存在AR物品,会发生什么情况:

我们应用了一种效果,仅计算一个效果就占用了每一帧所有计算的26.4%。 这使相机的速度降低到了每秒10帧的疯狂水平。
当我在这里挖掘并查看这个大瓶颈时,我发现完成大部分工作的最重要的事情是使用密集的NSDispatchData。

这是NSData的子类。 而所有这些都是通过range函数获取字节的。 这是一个简单的功能。 它所做的就是从数据中获取一些字节并将其放置在其他位置。 它并不太疯狂,但是显然,它在内部所做的所有事情都占了这26%的18%。
规则1这是一个NSData,并且正在获取字节。 那是一个简单的Objective-C,但是如果遇到了瓶颈,那就是时候改用C了。 由于瓶颈在一次调用中以获取浮点值,因此可以只使用memcpy()。 使用memcpy(),您可以将数据块移动到其他位置。 减少了很多开销。
如果您看起来像NSData,那么这些类就像数千行。 所以那里有很多东西。 在这种情况下,我们将原稿显示为红色。

在这里,您得到一个范围,获取一些字节并将其复制到缓冲区中。 memcpy()版本几乎是同一回事。 它看起来并不复杂,并且做的事少得多。

当我们更改它并再次运行它时,通过将那一行更改为memcpy(),事情从26%变为0.6%。 然后,帧速率急剧上升。
规则2如果您正在执行某种渲染应用程序,或者正在执行诸如加载栏之类的操作,则应避免过度绘制。 很多情况下,事件发生的速度将超过每秒60帧。 在这种情况下,您可以使用CADisplayLink限制UI的此更新。 它具有一个名为preferredFramesPerSecond的属性。 仅适用于iOS 10或更高版本。 对于较旧的用户,您必须手动进行操作,但仍然有用。

您可以设置所需的帧率。 很多时候像加载条一样,我将其设置为每秒15帧左右,因为这并不重要。 它不必每秒更新60帧。 如果两种方法看起来都一样,这可以节省您实际要做的许多工作。
规则3使用IMP缓存。 这仅对Objective-C有用。 在InObjective-C中,当您在后台调用方法时,实际上是在调用Objective-C消息发送函数(objc_msgSend())。 如果看到跟踪中的此调用占用了大量时间,则实际上可以轻松摆脱这一点。 从根本上讲,它是缓存表,在其中通过给函数名称指定某种方法来查找函数指针。 无需每次都进行查找,您可以缓存函数指针并直接调用它。 通常至少快两倍。

如果没有缓存的指针,则可以通过调用methodForSelector:来获取它。 然后我们就像常规函数调用一样调用此方法。 您将选择器传入对象,然后再输入任何参数。
规则4不要使用ARC。 ARC会增加很多开销。 在您的代码中,您正在发生所有这些事情,并且所有内容都带有保留和释放。 它会做很多事情,而且会做更多的事情。 因此,如果您真的想进行优化,并且看到跟踪中有很多保留和释放调用,而这些调用又占用了大量时间,则可以切换到不使用ARC,这需要做很多工作。
也很难让您的队友同意这样做而不为之生气。
如果Swift对性能特别敏感,请不要使用它。 Swift是一种很好的语言。 它具有一些非常整洁的功能。 但是它也使用了更多内部的样板以获得高级别的功能。 如果您想提高速度,则应尽可能靠近装配体,并尽可能靠近低层的东西。 这样会更快,因为它自动减少了代码。
如果您认为有趣的话正在研究中,那么Marcel Weiher会写一本非常不错的书,名为“ iOS和MacOS:性能调优”。 它确实深入了很多这些东西,并且进一步深入了很多。 我也有一个视频系列。 我为RayWenderlich制作视频。 我做了一个实用的乐器系列,它进行了更深入的介绍,对这些问题进行了更多解释,并提供了一些示例。 因此,如果您想专门了解有关乐器的更多信息,可以观看该视频系列。 然后是WWDC视频-有很多视频可以解释类似这样的性能问题。
录影带
在这里,您可以找到基于Luke的演讲的文章的第一部分。 在此处观看完整的演讲: