如何高效的准确的获取一个工程所有控制器的 viewdidload 方法的执行时间?

2017-03-14 15:23:15 +08:00
 changhogliang
先说说现在的做法,首先在启动时获取 objc_getClassList 获取项目中所有的类,然后看这个类是否有 viewdidload 方法,如果就 swizzle method,然后在替换的方法中间调原方法,前后记下时间,然后就可以获取方法的执行时间,这种做法有一个问题。如果项目中有很多控制器,在启动时就有大量的控制器需要交换方法,就会导致在早期的机型(5s)CPU 使用率过高,主线程卡顿的问题,而且多次启动后手机发热严重。我测了下方法的执行,发现瓶颈是在 method_exchangeImplementations(originalMethod, newMethod);这句又是系统的方法,想了一周,都没有想到好的办法。有没有别的办法的朋友?
2907 次点击
所在节点    iDev
10 条回复
chipmuck
2017-03-14 17:09:07 +08:00
写个父类,所有 vc 都继承这个 vc 类,然后在父 vc 类中的 +load 里进行 hook ?
loveuqian
2017-03-14 17:10:04 +08:00
论基类的重要性
changhogliang
2017-03-14 17:30:37 +08:00
@chipmuck 我这是做 sdk 的,不能这样干。
changhogliang
2017-03-14 17:32:59 +08:00
现在想了一个办法,在启动时让进行 hook 的线程隔一段时间 sleep 一下,不知道这样干有没有什么潜在风险。
chipmuck
2017-03-14 17:38:37 +08:00
@changhogliang 在 sleep 的期间有个 vc 被创建了,但是还没有 hook 到,就无法监控了。
changhogliang
2017-03-14 17:43:54 +08:00
@chipmuck 存在这个问题,不过为了保证性能,实在是没有什么别的好办法。
coa
2017-03-15 00:37:04 +08:00
不明白启动时为嘛一定要取得所有类,不应该直接针对 UIViewController 进行 hook 吗?还有其他类有 viewdidload 方法?这阶段对其他类的自省估计得浪费不少时间。。

+load 不用起一个基类啊,正常姿势不是放在 category 么?+load 又不会被覆盖,也没啥侵入性, SDK 可以用吧。。

sleep 一下估计不是好方法,莫名想起网络请求不用回调,估摸着 delay 个零点几秒再刷新 UI 这样的无语做法。。程序应该足够确定不应该依赖这一类“估摸”。。。

不清楚 method_exchangeImplementations 为何会占用大量资源?这不是常用的 Method Swizzle 方式么。。实在是这个方法有问题,要不试试将 viewdidload 选择器 hook 到 objc_msgForward 的实现,强行进入消息转发,再 hook forwardInvocation ,再转 viewdidload 的实现?不过到 forwardInvocation 之前还有不少动作,感觉时间也不少。。还是觉得 method_exchangeImplementations 不该有问题。。。

感觉朝 Method Swizzle 进行优化方向好像不大对,还是找找看有没有其他更直接的取得执行时间的方法靠谱些。。。
changhogliang
2017-03-15 09:30:02 +08:00
@coa1. 对 UIViewController 进行 hook 如何可以获取它子类的 viewdidload 的执行时间?放在分类里,应该对谁添加分类?我觉得必须对项目中创建的控制器进行 hook 才能正确获取方法执行时间,如果是 sdk ,你怎么获取项目中创建的控制器呢?
2.其实我 hook 的不止这一个方法,控制器的生命周期方法都有 hook ,如果 hook 几个,几十个类没有问题,如果 hook 几百个的话,在 5s 上面就发热严重,我把 method_exchangeImplementations 注释掉,问题就不存在了。
3.获取一个方法的执行时间,肯定是要在前面记个时间,方法执行后记个时间,这种除了 hook 应该没有别的办法了吧, hook 就绕不开 method_exchangeImplementations ,感觉这点消耗性能的操作必须要做。
coa
2017-03-15 23:21:08 +08:00
@changhogliang 明白了,需要子类 viewdidload 后再执行,这种情况下 hook UIViewController 确实不管用。

hook 除了 method_exchangeImplementations ,还有一个就是上边说的,将 originalMethod 的选择器指向 objc_msgForward 函数地址,在消息转发阶段进行有关操作。具体参考可翻下 Aspects 的源码。 Aspects 可以直接前后都 hook ,就是不知道控制器多的话会不会和 method_exchangeImplementations 一样出现发热问题。 SDK 允许引入第三方依赖的话可以先拖进去试一下,就千来行代码,体积应该可以接受,不允许再参考着自己写。如果同样发热的话估计得另寻他法了。。。
changhogliang
2017-03-16 14:10:24 +08:00
@coa 先谢谢了,这是一个思路,可以试试。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/347387

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX