页面加载性能监控可能存在的数据误差问题

前言

App 端性能监控已经不是新鲜事了,很多大小厂都在持续得做指标建设。其中页面加载过程监控是很重要的一块。

问题

监控页面加载的过程就需要监控页面创建和展示的各个时间点,我们通常的做法就是 hook UIViewController 的 viewDidLoad: 和 viewDidAppear: 等生命周期方法: -w250

正常输出 log:

-w250

但是这种方式存在一个问题,如果我们改一下 cus_ViewController 中两个方法的实现: -w250

会发现输出的结果并没有算上 sleep 的时间,这个结果显然不是我们想要的。

我们 hook 的是父类 UIViewController 的生命周期方法,子类的方法中通常先 call super 然后再执行自己的逻辑,如果是上面这种实现方式,子类自己的实现逻辑就没有算上,图上圈出来的部分就是实际没有算上的时间: -w250,-h600 也就是 UIViewController viewDidLoad 之前和 UIViewController viewDidAppear 之后的时间没有算上,前者的误差可能还少点,因为大部分逻辑一上来就是先 call super,但是后者的误差可能就会比较大了,毕竟子类在自己的 viewDidAppear 方法里执行业务逻辑是很常见的。

解决

其实我们想办法 hook 住子类的生命周期方法就能解决问题。 UIViewController 的初始化方法也就只有以下三个:

- (instancetype)init;
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

我们可以分别 hook 住这几个初始化方法,在创建子类的时候就再将他们的生命周期方法也 hook 一下: -w250

运行一下发现可以得到正确的值了: -w250

在网上有看到别人利用 「KVO 系统会自动帮忙创建一个子类」的方法解决这个问题,不知道有没有其他更好的方式。