美文网首页
浅谈ARC下hook"performSelector:

浅谈ARC下hook"performSelector:

作者: F森 | 来源:发表于2017-10-26 17:04 被阅读30次

    如果你尝试hookperformSelector:withObject:swzzle该方法,你会发现一运行很快就会崩溃,爆出EXC_BAD_ACCESS野指针错误。

    下面上demo:

    #import "NSObject+Hock.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (Hock)
    
    + (void)swizzleInstanceSelector:(SEL)originalSelector withSwizzledInstanceSelector:(SEL)swizzledSelector
    {
        Method originalMethod = class_getInstanceMethod(self, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
        if (originalMethod && swizzledMethod) {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
           [self swizzleInstanceSelector:@selector(performSelector:withObject:) withSwizzledInstanceSelector:@selector(hook_performSelector:withObject:)];
        });
    }
    
    - (id)hook_performSelector:(SEL)aSelector withObject:(id)object {
        NSLog(@"------------hook: object:%@ aSelector:%@--------------",object,NSStringFromSelector(aSelector));
        return [self hook_performSelector:aSelector withObject:object];
    }
    

    最后一次打印的内容是:

    ------------hook: object:<UIWindow: 0x7ffc0060a7e0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000005bdb0>; layer = <UIWindowLayer: 0x600000030a00>> aSelector:setWindow:--------------
    

    再往下走就崩溃了(黑人脸)!!!

    先看看UIWindowsetWindow:方法,这个方法

    AppDelegate.m 跑一下如下的代码:

        SEL sel = NSSelectorFromString(@"setWindow:");
        NSMethodSignature *signature = [[self.window class] instanceMethodSignatureForSelector:sel];
        NSLog(@"%lu",(unsigned long)signature.methodReturnLength);
        NSLog(@"%s",signature.methodReturnType);
    

    上面的代码就是通过NSMethodSignature来确定方法是否有返回值以及返回值的类型是什么。

    打印结果如下:

    2017-xx-xx 16:48:28.675 Demo[7521:1127858] 0
    2017-xx-xx 16:48:30.180 Demo[7521:1127858] (null)
    

    可以看到setWindow:是没有返回值的,崩溃关返回值什么事?是的,就是关返回值的事。

    ARC 环境下当调用一个方法时,需要知道这个方法的返回值类型及返回值的接受者是谁,这也是ACR下能够管理引用类型的一个重要因素。

    在执行 performSelector:withObject:方法时,该方法的返回值类型是id类型,而实际上selector方法的返回值有可能是void,如本例中的setWindow:,也就是ARC不知道返回值是什么类型的。

    在这种返回值是void的情况下,ARC视图返回一个值,但是实际上没有任何东西返回,当强制这么干的时候就会造成野指针。要解决这个问题可以兼容到MRC,在MRC下会根据实际情况决定是否返回一个值。

    怎么兼容MRC呢?前往 Build Phases > Compile Sources 给 NSObject+Hock.m 文件 加上-fno-objc-arc

    再次运行,It is work!

    整个过程就是如上所示,这也是解决hookperformSelector:withObject:过程中可能奔溃的方法。

    相关文章

      网友评论

          本文标题:浅谈ARC下hook"performSelector:

          本文链接:https://www.haomeiwen.com/subject/dvukpxtx.html