关于 Method Swizzling
其实已经算是挺熟悉了的,但今天在用的时候遇到了一个坑,觉得还是有必要记录一下的。
网上找到的资料一般都是以分类
的形式包装一下,例如:
1 | #import "NSObject+KGSwizzle.h" |
还有 《iOS 7 Programming:Pushing the Limits》
一书里面的 demo 也是使用分类的形式来撰写的。
但在我这边,其实不太想新增一个分类,写在 +load
里面简单的交换类A的实现为类B的方法即可。当我使用上面的方法进行交换时发现出现死循环了。
后来发现是需要使用 class_addMethod
为类B动态添加一个方法,然后用class_getInstanceMethod
重新获取地址后在进行交换才可以。
具体实现如下:
1 | // |
Note: 尽量把交换方法写在 dispatch_once 中,保证只执行一次。
最后,把该 swizzing 方法包装成一个通用方法:
1 | +(void)exchangeClass:(Class)cls_a selector:(SEL)sel_a withClass:(Class)cls_b selector:(SEL)sel_b { |
当你如下在 swizzling dealloc 的时候 XCode 会报错:
1 | [KGCorePlayerManager exchangeClass:[KGCorePlayerManager class] selector:@selector(ex_dealloc) withClass:[KGCorePlayerManager class] selector:@selector(dealloc)]; //ARC forbids use of 'dealloc' in a @selector |
那是因为 ARC 中不允许直接调用 dealloc 方法了。
可以用 NSSelectorFromString(@"dealloc")
替换@selector(dealloc)
这样取巧的方式绕过编译器的检查。
没有验证过这种骗过编译器的方式在真正运行的时候是否会出现运行时错误,查资料的时候,stackoverflow 上给出的建议是使用 associated 的方式为观察的类添加一个观察变量,在观察类销毁的时候,你就可以知道了。确实是一种不错的思路,强烈推荐看一下!
参考链接: