iOS 测试 iOS 页面加载时间测试

xinxi · 2018年10月02日 · 最后由 xinxi 回复于 2018年10月08日 · 4025 次阅读

前言

页面加载时间指的页面从创建到可见的时间.

严格意义上来说页面加载时间测试,更应该是页面的冷加载,不包含接口返回数据时间.

页面加载时间能反应代码中创建页面视图是否有过度绘制或者绘制不合理导致创建视图时间过长的情况.

UIViewController

UIViewController 是画面控制的中心类,包含导航条、标签条、工具条等多种功能界面,主要功能是用于控制画面的切换,其中的 view 属性管理整个画面的外观。

页面生命周期

viewDidLoad: 载入完成,可以进行自定义数据以及动态创建其他控件

viewWillAppear: 视图即将出现在屏幕之前

viewDidAppear: 视图已经在屏幕上渲染完成

viewWillDisappear: 视图即将从屏幕上移除

viewDidDisappear: 视图已经被从屏幕上移除

dealloc: 视图被销毁

image

测试方法

view 基类打点

一般项目代码都会继承UIViewController做一些封装,然后其他页面继承这个view基类.


页面开始创建点

- (void)viewDidLoad {
    [super viewDidLoad];
    //继承了UIViewController的viewDidLoad方法
    self.statusBarStyle = UIStatusBarStyleDefault;
    [self.view setBackgroundColor:[UIColor whiteColor]];

    NSLog(@"page-test-start:%@",NSStringFromClass([self class]));
    self.StartTime = [[NSDate date] timeIntervalSince1970];
}

页面展示结束点
- (void)viewDidAppear:(BOOL)animated{
     [super viewDidAppear:animated];
     //继承了UIViewController的viewDidAppear方法
    NSLog(@"page-test-end:%@",NSStringFromClass([self class]));
    // 用NSStringFromClass方法获取当前的页名称
    self.EndTime = [[NSDate date] timeIntervalSince1970];
    CGFloat rounded_up = round((self.EndTime-self.StartTime) * 1000);
    NSLog(@"page-test-total:%.2lf",rounded_up);
}


操作app并且使用idevicesyslog过滤关键字:

idevicesyslog | grep -e page-test-end -e  page-test-total


output:

Sep 30 16:33:06 xinxide-iPhone xxxxx[2195] <Notice>: page-test-end:HomeViewController
Sep 30 16:33:06 xinxide-iPhone xxxxx[2195] <Notice>: page-test-total:379.00
Sep 30 16:33:09 xinxide-iPhone xxxxx[2195] <Notice>: page-test-end:UserInfoViewControllerV2
Sep 30 16:33:09 xinxide-iPhone xxxxx[2195] <Notice>: page-test-total:239.00
Sep 30 16:33:12 xinxide-iPhone xxxxx[2195] <Notice>: page-test-end:LoginRegisterViewControllerV2
Sep 30 16:33:12 xinxide-iPhone xxxxx[2195] <Notice>: page-test-total:631.00
Sep 30 16:33:14 xinxide-iPhone xxxxx[2195] <Notice>: page-test-end:LoginViewControllerV2
Sep 30 16:33:14 xinxide-iPhone xxxxx[2195] <Notice>: page-test-total:567.00

hook 机制

第一种方法在你需要知道 view 的基类叫什么名字并且在代码中打点,这样做每次都有麻烦.

所以想使用拦截 viewDidLoad 和 viewDidAppear 这两个函数,就拦截器中打印时间就可以了.

Aspects 库是一个是 iOS 上的轻量级 AOP 库,https://github.com/steipete/Aspects, 另外 Aspects 封装了 iOS runtime 的特性

什么是 AOP?

简单来说,AOP(Aspect Oriented Programming) 是面向切面编程,主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。

参考:https://www.jianshu.com/p/addd4eac54ed

什么是 hook?

使它能够将自身的代码「融入」被勾住(Hook)的程序的进程中,成为目标进程的一个部分。API Hook 技术是一种用于改变 API 执行结果的技术,能够将系统的 API 函数执行重定向。

image

核心代码

在podfile引用如下:

target "UICatalog" do
  xcodeproj 'UICatalog.xcodeproj'
  pod 'YYKit'
  pod 'Aspects'
end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[getperformance new] performancethread];//获取性能数据

    /**
     *  事件拦截
     *  拦截UIViewController的viewDidLoad方法
     */
    [UIViewController aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo){
        NSLog(@"%@ 对象的viewDidLoad调用了",aspectInfo.instance);
        self.StartTime = [[NSDate date] timeIntervalSince1970];
        /**
         *  添加我们要执行的代码,由于withOptions是AspectPositionAfter。
         *  所以每个控制器的viewDidLoad触发都会执行下面的方法
         */
    } error:NULL];

    /**
     *  事件拦截
     *  拦截UIViewController的viewDidAppear方法
     */
    [UIViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo){
        NSLog(@"%@ 对象的viewDidAppear调用了",aspectInfo.instance);
        self.EndTime = [[NSDate date] timeIntervalSince1970];
        CGFloat rounded_up = round((self.EndTime-self.StartTime) * 1000);
        NSLog(@"%@页面,页面加载耗时:%.2lf",aspectInfo.instance,rounded_up);
        /**
         *  添加我们要执行的代码,由于withOptions是AspectPositionAfter。
         *  所以每个控制器的viewDidLoad触发都会执行下面的方法
         */
    } error:NULL];
    return YES;
}


output:

2018-10-02 18:11:44.361065+0800 UICatalog[22872:5780236] <AAPLAlertViewController: 0x7ffd0cf2c870>页面,页面加载耗时:518.00
2018-10-02 18:11:50.289907+0800 UICatalog[22872:5780236] <AAPLPageControlViewController: 0x7ffd0ce39080>页面,页面加载耗时:523.00
2018-10-02 18:11:52.131938+0800 UICatalog[22872:5780236] <AAPLDatePickerController: 0x7ffd0ce3a550>页面,页面加载耗时:631.00


代码地址: https://github.com/xinxi1990/iOSPerformanceTest.git

结语

app 专项测试已经做了大半年了,从无到有,从有到持续优化.
对我而言有两点思考.

1.专项测试测出来的数据结果,其实并不是记录一个数值而已,更需求了解其背后的技术特性.

2.测试结果是否能提供给开发同学优化的价值.

共收到 4 条回复 时间 点赞

一直在想基于测试设备的专项测试有没有太大的意义

2楼 已删除
恒温 回复

有些还是有意义吧,比如内存测试、稳定性测试,的确有些专项测试,测出来问题,解决也很难,或者说是无法解决

请问一下,这个是不是必须要有 app 的源码才能进行测试加载时间呢?

ChenSJM 回复

是的

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册