UIProgressView在tvOS上的性能

在过去的几个月中,我很高兴能够开发tvOS应用程序。 针对tvOS的开发与iOS非常相似,这使得从一开始就可以很轻松地进行工作。 在对其中一项功能进行多次迭代之后,我们偶然发现了其中一种集合视图带来的性能下降。 在Instruments上花费的时间揭示了我们可以应用的许多潜在优化,其中包括为我们的集合视图缓存布局属性,对我们的滚动算法进行进一步的优化等。所有优化为除了一个不需要的集合视图之外的所有内容都提供了出色的结果表现良好。 除了一个集合视图外,其他所有内容均以惊人的60 fps速度运行。 这很快就变成了我的爪子上的荆棘,我开始执行一项任务以弄清为什么会发生这种情况。

我没有指望单击Xco​​de中的“配置文件”按钮的次数。 我开始剥离UI元素,更深入地了解配置文件堆栈,最后我在针对tvOS优化的黑色犯罪故事中遇到了一个嫌疑犯。 所有证据都表明, UIProgressView是罪魁祸首。 现在我们终于发现了一个很大的弊端,是时候该弄清楚如何解决这个问题了。 但是在我们进入解决方案之前,我想提出一个我的理论来说明为什么会这样。 因为我不知道UIProgressView的内部工作原理,所以我无法将我的理论作为事实提出来,但是如果您继续研究,我认为您会同意这是有道理的。

我最初认为这是Apple的错误,并且打算提出警告,但是经过更多的考虑,这更多的是Apple提供的实现成本,这使我们不适合在这种情况下使用。 话虽如此,我们没有在新的Apple TV上看到相同类型的帧丢失,这意味着随着时间的流逝,此问题将自行解决。 我们不能只是坐下来等我们的用户升级硬件,因此我们推出了自己的解决方案,该解决方案将更适合我们的需求,并以我们想要的方式扩展。

由于UIProgressView旨在在尽可能多的情况下工作,因此Apple选择了UIVisualEffectView 。 我知道这个选择; 不幸的是,如上所述,这并不能很好地扩展,因为我们一次显示了十到十一个视图,所有视图都使用了此实现。 根据设备的不同,它可以使帧丢失达到20 fps或更高。 另外,我们的设计不必依赖UIVisualEffectView,因为我们添加了渐变以确保进度视图始终对用户可见。 您可以说Apple提供的原始实现针对我们的用例进行了过度设计。 可能还有其他原因导致它对我们而言效果不佳,我们用来解决该问题的解决方案是制作自己的进度视图版本,该版本不受UIVisualEffectView的支持。

因为我们希望它可以替代UIProgressView ,所以从UIProgressView复制了公共API。 它使开始使用视图变得更加容易,因为我们只需要更改要使用的类即可,而不必更新对该类进行的所有方法调用。

我们的替代产品包括两个CALayer ,一个外层代表总进度,另一个内层代表当前进度。 外层的拐角半径等于进度视图高度的一半; 这使它具有与UIProgressView相同的形状。 对于动画,当我们调用setProgress(_ progress:Float, animation :Bool = false)时,我们将提供一个CABasicAnimation ,并将其添加到内层。

由于CALayer缺乏使用约束的能力,因此将图层和动画包裹在常规的UIView中 ,使其更易于使用。

将这个新的进度视图放入我们的应用程序后,我们的应用程序再次开始达到60 fps,用户获得了他们应有的性能。