美文网首页
浅谈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