Runtime系列(Method Swizzling)
2016-08-05 16:22
316 查看
原文来自:http://www.jianshu.com/p/ccbe23b0ac0a
前言
记得《大话西游2》中有这么个桥段,紫霞仙子和猪八戒中招移魂幻影大法后灵魂互换,当时看的也是泪流满面。。而Method Swizzling就是传说中的移魂幻影大法!身体还是那个身体,但是灵魂已被互换,同样的身体言行举止都变成被换对象。正文
![](http://upload-images.jianshu.io/upload_images/329694-447cdf23ea52885a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Mthod Swizzling.png
代码很好理解,如果还在想为什么不会陷入死循环,是时候重温这部经典影片了。
如果交换后再交换呢?
![](http://upload-images.jianshu.io/upload_images/329694-b725ebbdb6afb5d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
交换两次.png
显然,偶数次交换后方法的实现不变
说一下使用Method Swizzling的几个注意点:
最好在
+ (void)load中实现交换
通常我们使用这个技巧时,希望在整个项目都可以实现交换效果,毫无疑问
+ (void)load是最佳选择。只要当前类参与编译,在程序启动后就会调用,并且仅调用一次,这样就防止了
IMP出现偶数次交换的情况。在继承关系下,先调用父类的
+ (void)load再调子类,继承关系下的分类调用关系刚好相反。
既然
+ (void)load只会调用一次,为什么还要加
dispatch_once?
dispatch_once
如果你刚好知道
+ (void)initialize的存在,可能会觉得在
+ (void)initialize中实现交换也未尝不可,毕竟当外界调用当前类的方法时,会提前调用initialize,好像也是只调一次。
首先要纠正一个错误:initialize并非只会调用一次,如调用子类的某个方法,并且只实现父类的initialize,这个时候父类的initalize会调用2次,所以加上
dispatch_once可以确保交换代码只执行一次。
除此之外,swizzle写在initialize中当遇到并发情况时,程序仍然有可能诡异的crash掉,所以要加
dispatch_once。
如果swizzle写在
+ (void)load是不是就不用加
dispatch_once了,因为不涉及并发,而且
+ (void)load不是只会调用一次么?load是系统在调,但同样支持手动调用,为防止特殊情况发生,加
dispatch_once总没错。
swizzle多为交换系统自带方法(下面两条普遍适用)
在交换时要调用系统方法的原始实现,即调用super
为避免出现命名与系统某自带方法相同,方法名最好带上前缀
写在最后
更好的写法是,在load的dispatch_once内部末尾加上这段代码![](http://upload-images.jianshu.io/upload_images/329694-57375340464d48bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
附加代码.png
让我们先来搞清楚这段代码究竟是在做什么:
第一句是添加
IMPswizzlingMethod到
SELoriginSel中(只是添加,不会覆盖orginSel的原有实现),当且仅当
originSel为当前类的父类方法时才能添加成功。如果添加成功将
SELswizzlingSel的实现用原有的
IMPoriginMethod覆盖,关系如下:
![](http://upload-images.jianshu.io/upload_images/329694-85f4c997d9079ba4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
相关文章推荐
- 拓扑排序
- 排序算法总结(三)选择排序【Select Sort】
- SSH学习之Hibernate session的方法全集
- leetcode single number系列
- js写的5秒钟倒计时跳转
- bzoj3670 noi2014动物园(kmp)
- 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作
- js实现精确到毫秒的倒计时效果
- resource
- Linux驱动开发 -- 打开dev_dbg()
- (13)递增递减运算符 (14)字符串运算符 (15)赋值运算符 (16)switch case语句
- 写给想当程序员的朋友
- Android平台Native开发与JNI机制详解
- 51Nod-1021-石子归并
- Python进程、线程、协程详解
- PasswordHasher
- centos6.5-64bit安装htop
- Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】
- hdu 2647 Reward(拓扑排序)
- 分类算法—决策树