method swizzling学习

参考1
参考2

Method Swizzling是一个改变selector的实际实现的一个方法。比如有A,B方法,通过Method Swizzling方法可以实现调用A方法时,实际上是在调用B方法,实现了偷梁换柱的黑魔法。

使用场景:完全改变一个方法的实现
比如viewDidAppear.方法有:
1.继承后重写(不要调用super方法)。
2.使用分类实现重名方法,那么在分类会覆盖原类中得方法。
3.使用method swizzling。

示例
更改UIImage的imageNamed方法,当传入的image为空是打印出错。

#import 
@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.私有方法也能替换

你可能感兴趣的:(method swizzling学习)