Gotta Go Fast:在iOS中构建速度。 第2部分

有时,您会发现自己的应用无法正常运行。 因此,这里提供了一些您可以使用的工具以及可以使事情变得更好的最佳实践。

这是本文的第二部分,基于2017年国际移动开发者大会MBLT DEV的Fyusion的iOS工程师,RayWenderlich.com上的iOS开发教程作者Luke Parham的主题演讲。

在这里您可以找到第一部分。 在这里观看完整的演讲:

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

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

红色表示您的标签带有白色背景。 然后,它们位于另一个白色背景之上,并且由于某种原因,它们未设置为不透明。 因此,搅拌器将这些颜色(白色和白色)混合在一起,从而得到白色。 对于具有红色的每个像素,它都会进行额外的计算而没有任何好处,但是背景仍然会变为白色。

为避免这种情况,只要它们在同一颜色上具有相同的颜色,就可以使它们尽可能不透明。 如果子视图具有相同的背景色,则不需要混合。 您所要做的就是将图层的不透明度设置为1,然后确保设置了背景色。 如果您的背景颜色是透明的,则它永远不会是不透明的。

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

如您所见,它们都是黄色的。 在iPhone 5上,它们的速度非常慢。 这是因为屏幕外渲染比alpha混合差得多。 它使GPU停顿。 最终必须在GPU和CPU之间来回进行额外的计算,因此您将获得大多数情况下不必要的额外停顿。

下一条规则:不要使用转角半径属性。 如果您有一个视图并设置了view.layer.сornerRadius,则始终会引入屏幕外渲染。 相反,您可以使用贝塞尔曲线路径和早期的同类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帧。 如果两种方法看起来都一样,这可以节省您实际要做的许多工作。

规则三

使用IMP缓存。 这仅对Objective-C有用。 在InObjective-C中,当您在后台调用方法时,实际上是在调用Objective-C消息发送函数(objc_msgSend())。 如果您看到此调用在跟踪中占用大量时间,则实际上可以轻松摆脱这种情况。 从本质上讲,它是高速缓存表,您可以通过为其指定一些方法的名称来查找函数指针。 不必每次都进行查找,您可以缓存函数指针并直接调用它。 它通常至少快两倍。

如果没有缓存的指针,则可以通过调用methodForSelector:来获取它。 然后我们就像常规函数调用一样调用此方法。 您将选择器传入对象,然后再输入任何参数。

规则#4

不要使用ARC。 ARC会增加很多开销。 在您的代码中,所有这些事情都在发生,并且充满了保留和释放。 它会做很多事情,而且会做更多的事情。 因此,如果您真的想进行优化,并且发现跟踪中有很多保留和释放调用,而这些调用又占用了大量时间,则可以切换到不使用ARC,这需要做很多工作。

也很难让您的队友同意这样做而不为之生气。

如果Swift对性能特别敏感,请不要使用它。 Swift是一种不错的语言。 它具有一些非常整洁的功能。 但是它也使用了更多内部的样板来获得高级功能。 如果您想提高速度,则应尽可能靠近装配体,并尽可能靠近低层的东西。 这样会更快,因为自动代码更少。

如果您认为有趣的话正在研究中,那么Marcel Weiher会写一本非常不错的书,名为“ iOS和MacOS:性能调优”。 它确实深入了很多这些东西,并且进一步超越了这个东西。 我也有一个视频系列。 我为RayWenderlich制作视频。 我做了一个实用的乐器系列,它更加深入,并且对这些问题进行了更多解释并提供了一些示例。 因此,如果您想专门了解有关乐器的更多信息,可以观看该视频系列。 然后是WWDC视频-有很多视频可以解释类似这样的性能问题。

2018年MBLT DEV会议将于2018年9月28日在莫斯科举行。再有20多位专家将分享他们的专业知识,谈论他们实现的有用工具以及讨论Android和iOS中的最新技术更新。

您有什么要分享的吗? 加入会议阵容:在6月30日之前填写CFP,并获得一笔用于支付旅行和住宿费用的赠款。

还没准备好发表演讲吗? 加入会议参加者以提高您的技能。 买一张票