OC runtime 提供了动态替换Method 实现的能力,加上category的使用,能够实现一种叫 swizzle的技术,从而给问题定位提供了一种方法。app
举个例子,NSNotificationCenter 注册的observer 是经过assign 方法保留observer引用(而不是weak 或 retain、strong),这样的话若是某个observer只是注册而没有注销,那么这个observer释放后,NSNotificationCenter 发送通知时将找不到这个observer,由于这个observer已经成了野指针,从而发生crash。spa
那么究竟是那个observer 只注册而没有注销呢? 能够经过给 NSNotificationCenter 增长一个category ,在category中经过swizzle 给原来的注册与注销方法添加log 来查看。指针
category的头文件:code
增长了swizzle 类方法,在app 启动时调用server
/* * NSNotificationCenter+TestHook.h */ #import <Foundation/Foundation.h> @interface NSNotificationCenter (TestHook) + (void) swizzle; @end
实现,增长两个hook 方法,分别给注册和注销方法添加log:递归
注意hook方法不能在头文件暴露以防被直接调用,由于在使用method_exchangeImplimentaions以前,直接调用会发生递归。rem
#import "NSNotificationCenter+TestHook.h" #import <objc/runtime.h> @implementation NSNotificationCenter (TestHook) -(void)hook_addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject{ NSLog(@"====== add observer for:%@, selector: %s, class %s", aName, sel_getName(aSelector), class_getName([observer class])); [self hook_addObserver:observer selector:aSelector name:aName object:anObject]; } - (void)hook_removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject{ NSLog(@"====== remove observer for:%@, class %s", aName, class_getName([observer class])); [self hook_removeObserver:observer name:aName object:anObject]; } +(void)swizzle{ Method ori_Method = class_getInstanceMethod([NSNotificationCenter class], @selector(addObserver:selector:name:object:)); Method my_Method = class_getInstanceMethod([NSNotificationCenter class], @selector(hook_addObserver:selector:name:object:)); method_exchangeImplementations(ori_Method, my_Method); Method ori_remove = class_getInstanceMethod([NSNotificationCenter class], @selector(removeObserver:name:object:)); Method my_remove = class_getInstanceMethod([NSNotificationCenter class], @selector(hook_removeObserver:name:object:)); method_exchangeImplementations(ori_remove, my_remove); } @end
而后在应用AppDelegeate中调用 :get
.... #import "NSNotificationCenter+TestHook.h" ... @implementation MyAppDelegate ... - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [NSNotificationCenter swizzle]; ... } ... @end
这样就能清楚的看到哪些observer注册了哪些通知,以及在何时注销了通知。it