首页   注册   登录
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/
iOS 开发实用书单
iPhone App Development: The Missing Manual
Cocoa and Objective-C: Up and Running
Cocoa Programming for Mac OS X
深入浅出设计模式 Head First Design Patterns
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
宝塔
V2EX  ›  iDev

请教一个 Swizzle method 的问题.

  •  
  •   xieweizhi007 · 2016-02-25 12:39:00 +08:00 · 2679 次点击
    这是一个创建于 1361 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想通过JRSwizzle来对UIViewController的一些生命周期的方法进行时间统计.

    代码如下:

    [self jr_swizzleMethod:@selector(viewDidLoad) withMethod:@selector(ri_viewDidLoad) error:nil];
    
    - (void)ri_viewDidLoad {
        NSDate *start = [NSDate date];
    
        [self ri_viewDidLoad];
    
        NSDate *end = [NSDate date];
        NSTimeInterval elapsed = [end timeIntervalSinceDate:start];
    
        NSLog(@"Elapsed:%f(s)",elapsed);
    }
    

    可是我在 view controller 的- viewDidLoad方法中执行 sleep(), 是采集不到这个时间的, 请问这里有什么问题吗?

    第 1 条附言  ·  2016-02-25 19:18:17 +08:00

    谢谢各位, 现在贴出一些代码, 请大家看看有什么问题

    Category 类:

    @interface UIViewController (ActivityTrace)

    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
        [self jr_swizzleMethod:@selector(viewDidLoad)
                    withMethod:@selector(ri_viewDidLoad)
                         error:nil];
        [self jr_swizzleMethod:@selector(viewDidAppear:)
                    withMethod:@selector(ri_viewDidAppear:)
                         error:nil];
        [self jr_swizzleMethod:@selector(viewDidDisappear:)
                    withMethod:@selector(ri_viewDidDisappear:)
                         error:nil];
        });
    }
    
    #pragma mark - Swizzled method
    
    - (void)ri_viewDidLoad {
        NSDate *start = [NSDate date];
    
        [self ri_viewDidLoad];
    
        NSDate *end = [NSDate date];
        NSTimeInterval elapsed = [end timeIntervalSinceDate:start];
    
        NSLog(@"Elapsed:%f(s)",elapsed);
    
        if (!kIsRichAPMVIPUser || [[self class] _isClassNotTrackable:[self class]]) {
            return;
        }
    }
    ... 省略
    

    某个 ViewController.m

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    
        //! sleep 的这个值不会影响到 ri_viewDidLoad
        sleep(2);  
    }
    
    第 2 条附言  ·  2016-02-26 14:48:12 +08:00
    目前的做法的跟 @wezzard 说的差不多, 缺点就是会影响性能并且比较复杂.
    22 回复  |  直到 2017-02-20 10:57:14 +08:00
        1
    randm   2016-02-25 12:49:58 +08:00
    你要用 ri_viewDidLoad
        2
    xieweizhi007   2016-02-25 14:39:27 +08:00
    @randm 这里是没问题的, 用 ri_viewDidLoad 就会死循环啦. 因为 ri_viewDidLoad 里面调用的 ri_viewDidLoad 其实是原来的 viewDidLoad 方法.
        3
    zhicheng   2016-02-25 16:02:32 +08:00
    1. 你想统计时间,这和 MethodSwizzling 有什么关系?
    2. 你 Swizzling viewDidLoad 有什么用?
        4
    xieweizhi007   2016-02-25 16:20:11 +08:00
    @zhicheng , 我是想通过这种方法来统计所有 Controller 的生命周期的运行效率.
        5
    chmlai   2016-02-25 16:33:02 +08:00
    代码看起来没有错, 分别在 ri_viewDidLoad 和 viewDidiLoad 里面 Log 一下看看
        6
    xieweizhi007   2016-02-25 16:54:55 +08:00
    @chmlai 原始的 viewDidLoad 也不需要 log 的, sleep 之后确实会卡顿. 而 ri_viewDidLoad 方法却是不正确的.
        7
    LINAICAI   2016-02-25 17:21:48 +08:00
    [self ri_viewDidLoad];
    这不对吧,不是应该[super ri_viewDidLoad];??
        8
    juxingzhutou   2016-02-25 18:57:42 +08:00
    你的 jr_swizzleMethod 是在哪里调用的?我觉得问题可能在 swizzling 的次数上。

    贴上更完整的代码有利于大家判断。
        9
    juxingzhutou   2016-02-25 18:58:30 +08:00
    @LINAICAI method swizzling 就是调用自身 selector 来调用原版方法的。
        10
    tedzhou   2016-02-25 19:06:37 +08:00
    是不是有其他信号相关的代码把线程唤醒了?
        11
    xieweizhi007   2016-02-25 19:18:48 +08:00
    @juxingzhutou 是的是的.
        12
    xieweizhi007   2016-02-25 19:19:03 +08:00
    @tedzhou 没有, 你可以看看.
        13
    tedzhou   2016-02-25 20:02:30 +08:00
    swizzle 不能把 subClass 的方法也交换的哦
        14
    juxingzhutou   2016-02-25 20:07:57 +08:00   ♥ 1
    13 楼说得对,我再补充解释一下。你的代码的问题是这样的,实际上你 swizzling 的方法是子类中的`[super viewDidLoad]`这个方法。

    也就是说 sleep 是在你的 ri_viewDidLoad 方法执行完之后才执行的,`[super viewDidLoad]`执行的才是 ri_viewDidLoad 方法。
        15
    xieweizhi007   2016-02-26 09:18:45 +08:00
    @tedzhou
    @juxingzhutou

    我大概懂了, 谢谢 ^ ^
        16
    wezzard   2016-02-26 14:14:30 +08:00
    我建議你啓動時掃描所有 classes 然後找到目標做 is-a swizzle ,做一個 wrapper wrap 住所有要統計的 class ,控制住所有消息發送。但是就是肯定會影響性能。
        17
    xieweizhi007   2016-02-26 14:47:06 +08:00
    @wezzard 我目前就是这样做的, 是有性能影响 😀
        18
    Python666666   2017-02-08 10:32:20 +08:00
    @xieweizhi007 可以分享一下你的解决方案吗
        19
    xieweizhi007   2017-02-08 19:23:15 +08:00
    @Python666666 跟 @wezzard 说的方案一样
        20
    Python666666   2017-02-14 15:16:56 +08:00
    @wezzard 不是很懂,可以分享一下 Demo 吗, [email protected],感恩
        21
    xieweizhi007   2017-02-14 22:29:20 +08:00
    @Python666666 你可以参考这个开源项目是怎样 hook 所有 HTTP 网络请求的 https://github.com/Flipboard/FLEX
        22
    Python666666   2017-02-20 10:57:14 +08:00
    @xieweizhi007 谢谢 遍历所有类,去除不是工程内的,再全部添加 hook 就可以了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2124 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 24ms · UTC 09:49 · PVG 17:49 · LAX 01:49 · JFK 04:49
    ♥ Do have faith in what you're doing.