如果你嘗試hookperformSelector:withObject:
并swzzle
該方法邑闺,你會發(fā)現(xiàn)一運行很快就會崩潰盒揉,爆出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];
}
最后一次打印的內(nèi)容是:
------------hook: object:<UIWindow: 0x7ffc0060a7e0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000005bdb0>; layer = <UIWindowLayer: 0x600000030a00>> aSelector:setWindow:--------------
再往下走就崩潰了(黑人臉)0贰:蘖铩符衔!
先看看UIWindow
的setWindow:
方法找前,這個方法
在 AppDelegate.m
跑一下如下的代碼:
SEL sel = NSSelectorFromString(@"setWindow:");
NSMethodSignature *signature = [[self.window class] instanceMethodSignatureForSelector:sel];
NSLog(@"%lu",(unsigned long)signature.methodReturnLength);
NSLog(@"%s",signature.methodReturnType);
上面的代碼就是通過NSMethodSignature
來確定方法是否有返回值以及返回值的類型是什么。
打印結(jié)果如下:
2017-xx-xx 16:48:28.675 Demo[7521:1127858] 0
2017-xx-xx 16:48:30.180 Demo[7521:1127858] (null)
可以看到setWindow:
是沒有返回值的判族,崩潰關(guān)返回值什么事躺盛?是的,就是關(guān)返回值的事形帮。
在ARC
環(huán)境下當(dāng)調(diào)用一個方法時槽惫,需要知道這個方法的返回值類型及返回值的接受者是誰,這也是ACR
下能夠管理引用類型的一個重要因素辩撑。
在執(zhí)行 performSelector:withObject:
方法時躯枢,該方法的返回值類型是id
類型,而實際上selector
方法的返回值有可能是void
槐臀,如本例中的setWindow:
锄蹂,也就是ARC
不知道返回值是什么類型的。
在這種返回值是void
的情況下水慨,ARC
視圖返回一個值得糜,但是實際上沒有任何東西返回,當(dāng)強制這么干的時候就會造成野指針晰洒。要解決這個問題可以兼容到MRC
朝抖,在MRC
下會根據(jù)實際情況決定是否返回一個值。
怎么兼容MRC
呢谍珊?前往 Build Phases > Compile Sources 給 NSObject+Hock.m
文件 加上-fno-objc-arc
再次運行治宣,It is work!
整個過程就是如上所示,這也是解決hookperformSelector:withObject:
過程中可能奔潰的方法砌滞。