什么是method swizzling?

来源:互联网 发布:linux aio 编辑:程序博客网 时间:2024/05/24 00:01

其实跟字面的意思很相近。方法的调和。可以去修改oc中两个方法的调用。

这张图看起来会比较形象


20130718230430859.png

就是把两个实现调换
具体的做法,
首先,用Categroy建立自己的方法。
在+load方法中去实现方法交换的代码(load可以保证被调用,其他方法都不靠谱)

        Method ori_Method =  class_getInstanceMethod([MYclass class], @selector(lastObject));          Method my_Method = class_getInstanceMethod([MYclass class], @selector(myLastObject));          method_exchangeImplementations(ori_Method, my_Method);

一定要记住,你的方法实现已经变了。


之前所说的消息转发虽然功能强大,但需要我们了解并且能更改对应类的源代码,因为我们需要实现自己的转发逻辑。当我们无法触碰到某个类的源代码,却想更改这个类某个方法的实现时,该怎么办呢?
可能继承类并重写方法是一种想法,但是有时无法达到目的。这里介绍的是 Method Swizzling ,它通过重新映射方法对应的实现来达到“偷天换日”的目的。跟消息转发相比,Method Swizzling 的做法更为隐蔽,甚至有些冒险,也增大了debug的难度。
这里摘抄一个 NSHipster 的例子:

#import <objc/runtime.h> @implementation UIViewController (Tracking) + (void)load {     static dispatch_once_t onceToken;     dispatch_once(&onceToken, ^{         Class aClass = [self class];         SEL originalSelector = @selector(viewWillAppear:);         SEL swizzledSelector = @selector(xxx_viewWillAppear:);         Method originalMethod = class_getInstanceMethod(aClass, originalSelector);         Method swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector);         // When swizzling a class method, use the following:        // Class aClass = object_getClass((id)self);        // ...        // Method originalMethod = class_getClassMethod(aClass, originalSelector);        // Method swizzledMethod = class_getClassMethod(aClass, swizzledSelector);        // 往类中添加方法        BOOL didAddMethod =             class_addMethod(aClass,                 originalSelector,                 method_getImplementation(swizzledMethod),                 method_getTypeEncoding(swizzledMethod));         //如果添加成功,就带类中不存在要替换的方法        if (didAddMethod) {             class_replaceMethod(aClass,                 swizzledSelector,                 method_getImplementation(originalMethod),                 method_getTypeEncoding(originalMethod));         } else {             //反之,类中已经有了想要替换的方法时            method_exchangeImplementations(originalMethod, swizzledMethod);         }     }); } #pragma mark - Method Swizzling - (void)xxx_viewWillAppear:(BOOL)animated {     [self xxx_viewWillAppear:animated];     NSLog(@"viewWillAppear: %@", self); } @end

上面的代码通过添加一个Tracking类别到UIViewController类中,将UIViewController类的viewWillAppear:方法和Tracking类别中xxx_viewWillAppear:方法的实现相互调换。
Swizzling 应该在+load方法中实现,因为+load是在一个类最开始加载时调用。dispatch_once是GCD中的一个方法,它保证了代码块只执行一次,并让其为一个原子操作,线程安全是很重要的。
如果类中不存在要替换的方法,那就先用class_addMethodclass_replaceMethod函数添加和替换两个方法的实现;如果类中已经有了想要替换的方法,那么就调用method_exchangeImplementations函数交换了两个方法的 IMP,这是苹果提供给我们用于实现 Method Swizzling 的便捷方法。
PS:这也是hook的一个方案哦




原创粉丝点击