MetricKit框架详细解析(九) —— Improving App Responsiveness(一)

版本记录

版本号 时间
V1.0 2021.05.16 星期日

前言

MetricKit由iOS13系统进引入,用来汇总和分析有关异常和崩溃诊断以及电源和性能指标的每个设备的报告。下面我们就一起来看下这个框架。感兴趣的可以看下面几篇文章。
1. MetricKit框架详细解析(一) —— 基本概览(一)
2. MetricKit框架详细解析(二) —— Improving Your App's Performance(一)
3. MetricKit框架详细解析(三) —— Reducing Your App's Memory Use(一)
4. MetricKit框架详细解析(四) —— Gathering Information About Memory Use(一)
5. MetricKit框架详细解析(五) —— Making Changes to Reduce Memory Use(一)
6. MetricKit框架详细解析(六) —— Preventing Memory-Use Regressions & Responding to Low-Memory Warnings(一)
7. MetricKit框架详细解析(七) —— Reducing Your App's Launch Time(一)
8. MetricKit框架详细解析(八) —— Reducing Disk Writes(一)

Overview

通过从应用程序的用户界面中删除hangs创建更直接的用户体验。

即时响应用户交互的应用给人以支持他们的工作流的印象。当应用程序实时响应手势和点击时,它会为用户带来一种直接操作屏幕上对象的体验。短时间内没有响应的应用程序会打破这种幻想,并使用户怀疑该应用程序是否能够正常运行。

人类的感知系统善于识别运动,并通过顺序动作将因果联系起来。人们很快就可以观察到两个事件之间的间隔作为暂停。在短短十分之几秒的延迟后,用户可能会觉得应用程序是惰性的,并且没有响应。因此,应用程序必须非常快速地对用户的行为做出反应,以保持用户对其行为的信心。


Detect Unresponsive Scrolling

当更新的内容尚未准备好进行下一次屏幕刷新时,滚动内容似乎会跳转或“hitch”。在“ Xcode Organizer”窗口的“滚动”窗格中或使用MetricKit查看hitch rate

注意:Session 10077: Eliminate Animation Hitches With XCTest


Detect App Hangs

挂起(“hang”)是应用无法响应的特定示例。 应用程序由于主线程不可用而无法更新视图内容或响应用户操作时挂起。 iOS会检测应用程序何时挂起,并通过MetricKitXcodemetrics organizer提供数据。 当主线程至少在250毫秒内没有响应时,iOS会跟踪应用程序挂起,您可以在metrics organizer中看到这些结果,如下所示。

Xcode Organizer将挂起率报告为应用程序无响应的每小时秒数。Organizer同时显示了典型用户所经历的中值悬挂率(median hang rate)和极端的90%悬挂率。 MetricKit提供与直方图相同的挂起率指标。

iOS支持具有不同硬件功能和性能特征的各种设备。在一种硬件模型上完美执行的代码可能会在另一种硬件模型上挂起。在各种不同的设备上测试应用程序的release版本,以发现仅在某些情况下才会出现的挂起。


Find the Cause of a Hang

应用程序挂起,因为在应用程序绘制到屏幕上时主线程不可用。发生这种情况有两个原因:主线程忙于执行代码,或者它被阻塞,等待资源可用或系统调用完成。使用Thread State Trace工具来发现哪种情况导致应用程序挂起。

Thread State Trace工具显示了线程状态的时间轴,以及描述了输入的系统调用,它们花费了多长时间以及iOS调度线程运行的时间。将此信息与System Call Trace工具结合使用,后者可提供每个线程进行的系统调用的次数和持续时间的摘要统计信息,以查看系统调用是否阻塞了您的主线程。

单击特定的系统调用,以查看该线程在进行系统调用时的回溯。使用此信息可以找出导致主线程挂起的主线程上的哪些函数或方法。


Remove Hangs from your App

确保您的应用仅在主线程上与UIKit交互。将所有其他操作定向到后台线程,operation queueGrand Central Dispatch队列。异步将工作分配到该队列或线程,并在完成后台工作后异步通知主线程或队列更新UI。不要将主线程与后台线程同步,也不要使主线程加入后台线程。这两个操作都会阻塞主线程,直到后台的工作完成为止,并且剥夺了应用程序执行并发操作的好处。

将UI更新分为准备显示数据和更新视图对象以在重绘视图时显示该数据。您的应用程序可以在后台进行准备,只需要使用主线程来更新其视图。向用户指示此准备工作正在进行中,使他们有机会酌情取消或执行其他任务。

例如,特定的应用程序使用UIRefreshControl来允许用户下拉table view,以从网络刷新其内容。 UIRefreshControl上的valueChanged事件会触发应用程序的UIViewController子类上的操作方法。当UIKit调用此操作方法时,该应用将使用NSURLSessionNSURLDataTask向服务器发出请求。完成网络任务后,应用程序将检查下载是否成功。如果是这样,则该应用程序从下载的数据中反序列化一个JSON对象,基于JSON对象中的字段更新其模型对象的属性,然后重新配置其视图以反映更新的模型。

在所有这些任务中,只有从UIKit调用操作方法和重新配置应用程序视图需要使用主线程。该应用程序可以异步将所有其他任务调度到后台,如下所示。


Minimize View Update Time

为了提供看起来像连续运动的平滑动画,iOS每秒至少更新屏幕60次。当您的应用程序位于前台时,主线程上的绘图代码需要在下一帧之前完成,以避免掉落帧并显得顿涩。花费很长时间绘制一帧会挂起该应用程序。

尽可能使用标准的UIKit视图,以确保有效的视图绘制。如果您需要自定义视图或控件以提供标准UIKit组件无法提供的功能,则其drawRect:方法应仅绘制到指定的矩形中。依靠drawRect:中先前准备的数据,不要使用此方法执行I / O或复杂的计算。仅绘制到作为drawRect参数传递的矩形中,避免对未绘制到屏幕上的视图组件进行昂贵的计算。

如果先前调用过setNeedsDisplay,则仅调用视图的drawRect:来更新一frame的视图。您仅应在需要更新视图的表示形式时调用setNeedsDisplay


Use Grand Central Dispatch or OperationQueue

随着设备上运行的线程数量的增加,iOS在CPU内核上调度每个线程的频率降低。任何单个线程(包括应用程序的主线程)都可以在核心上运行的时间更少。Grand Central Dispatch (GCD)NSOperationQueue都维护一个内部工作线程池,该线程池已根据设备的容量和负载进行了调整。使用这些技术,而不是创建自己的后台线程,可以确保在调度尽可能多的工作与允许iOS运行其他线程(包括主线程和操作系统任务)之间取得平衡。


Write Performance Tests to Spot Potential Hangs

对于必须在主线程上执行的代码,请创建XCTest性能测试以衡量运行代码所花费的时间。在measureBlock:块中执行相关代码。您可以接受代码块的平均运行时间作为基准,也可以编辑基准并将其设置为0.25s(iOS允许在记录挂起之前执行主线程的最长时间)。如果代码所需的执行时间明显长于基准时间,则性能测试将失败。

后记

本篇主要讲述了Improving App Responsiveness,感兴趣的给个赞或者关注~~~

你可能感兴趣的:(MetricKit框架详细解析(九) —— Improving App Responsiveness(一))