Method Swizzling是一个改变selector的实际实现的一个方法。比如有A,B方法,通过Method Swizzling方法可以实现调用A方法时,实际上是在调用B方法,实现了偷梁换柱的黑魔法。
使用场景:完全改变一个方法的实现
比如viewDidAppear.方法有:
1.继承后重写(不要调用super方法)。
2.使用分类实现重名方法,那么在分类会覆盖原类中得方法。
3.使用method swizzling。
示例
更改UIImage的imageNamed
方法,当传入的image为空是打印出错。
#import <objc/runtime.h>
@implementation UIImage (Swizzle)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
Class class = [self class];
// SEL:获取方法编号,根据SEL就能去对应的类找方法
SEL originalSelector = @selector(imageNamed:);
SEL swizzledSelector = @selector(custom_imageNamed:);
// 获取系统的方法(注意,如果是实例方法,使用class_getInstanceMethod)
Method originalMethod = class_getClassMethod(class, originalSelector);
// 获取自定义方法
Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
// 交换方法实现
method_exchangeImplementations(originalMethod, swizzledMethod);
});
}
+ (UIImage *)custom_imageNamed:(NSString*)imageName{
/**
* 调用[UIImage imageNamed:imageName]
说明:因为custom_imageNamed和imageNamed互相交换.所以下面方法调用的实际上是imageNamed:方法,不会造成死循环
*/
UIImage *image = [self custom_imageNamed:imageName];
if (!image) {
NSLog(@"图片是空得!");
}
return image;
}
@end
注意点
1.Swizzling要再+ (void)load或者+(void) initialize里实现。
说明:由于method swizzling 会影响到类的全局状态,所以要避免在并发处理中出现竞争的情况。+load方法是在程序启动时调用,可取。而+initialize是在第一次初始化使用类时候调用,虽然也是个选择,但是如果一直没有使用这个,那么也就不会使用method swizzling了。
2.Swizzling在dispatch_once中执行
说明:原子性可以保证代码只执行一次,而swizzling可以满足需要。
3.私有方法也能替换