V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
changhogliang
V2EX  ›  iDev

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

  •  
  •   changhogliang · 2017-03-14 15:23:15 +08:00 · 2875 次点击
    这是一个创建于 2810 天前的主题,其中的信息可能已经有所发展或是发生改变。
    先说说现在的做法,首先在启动时获取 objc_getClassList 获取项目中所有的类,然后看这个类是否有 viewdidload 方法,如果就 swizzle method,然后在替换的方法中间调原方法,前后记下时间,然后就可以获取方法的执行时间,这种做法有一个问题。如果项目中有很多控制器,在启动时就有大量的控制器需要交换方法,就会导致在早期的机型(5s)CPU 使用率过高,主线程卡顿的问题,而且多次启动后手机发热严重。我测了下方法的执行,发现瓶颈是在 method_exchangeImplementations(originalMethod, newMethod);这句又是系统的方法,想了一周,都没有想到好的办法。有没有别的办法的朋友?
    10 条回复    2017-03-16 14:10:24 +08:00
    chipmuck
        1
    chipmuck  
       2017-03-14 17:09:07 +08:00
    写个父类,所有 vc 都继承这个 vc 类,然后在父 vc 类中的 +load 里进行 hook ?
    loveuqian
        2
    loveuqian  
       2017-03-14 17:10:04 +08:00 via iPhone
    论基类的重要性
    changhogliang
        3
    changhogliang  
    OP
       2017-03-14 17:30:37 +08:00
    @chipmuck 我这是做 sdk 的,不能这样干。
    changhogliang
        4
    changhogliang  
    OP
       2017-03-14 17:32:59 +08:00
    现在想了一个办法,在启动时让进行 hook 的线程隔一段时间 sleep 一下,不知道这样干有没有什么潜在风险。
    chipmuck
        5
    chipmuck  
       2017-03-14 17:38:37 +08:00
    @changhogliang 在 sleep 的期间有个 vc 被创建了,但是还没有 hook 到,就无法监控了。
    changhogliang
        6
    changhogliang  
    OP
       2017-03-14 17:43:54 +08:00
    @chipmuck 存在这个问题,不过为了保证性能,实在是没有什么别的好办法。
    coa
        7
    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
        8
    changhogliang  
    OP
       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
        9
    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
        10
    changhogliang  
    OP
       2017-03-16 14:10:24 +08:00
    @coa 先谢谢了,这是一个思路,可以试试。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   969 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 20:12 · PVG 04:12 · LAX 12:12 · JFK 15:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.