runtime 第四部分method swizzling

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了runtime 第四部分method swizzling相关的知识,希望对你有一定的参考价值。

接上一篇 http://www.cnblogs.com/ddavidXu/p/5924597.html

转载来源http://www.jianshu.com/p/6b905584f536 

http://southpeak.github.io/2014/10/30/objective-c-runtime-2/

runtime的黑魔法,就是可以实现交换两个方法的实现,这就意味着我们可以修改系统的方法实现。

 

栗子:当UIViewController及其子类的对象调用viewWillAppear时,都会打印一条日志信息。

#import <objc/runtime.h>

@implementation UIViewController (Tracking)

+ (void)load {
        static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];         
        // When swizzling a class method, use the following:
                    // Class class = object_getClass((id)self);

        SEL originalSelector = @selector(viewWillAppear:);
                    SEL swizzledSelector = @selector(xxx_viewWillAppear:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
                    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
                        class_addMethod(class,
                originalSelector,
                method_getImplementation(swizzledMethod),
                method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
                        class_replaceMethod(class,
                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

 因为关于method swizzling方法的介绍非常多,就不详细说了,

大致原理图

技术分享

 

需要注意一下几点 

  • Swizzling应该总是在+load中执行

  • Swizzling应该总是在dispatch_once中执行

原因,method swizzling会影响到类的全局状态,避免在并发处理中出现竞争的情况,不管有多少个线程,确保代码只被执行一次。

选择器(selector)、方法(method)和实现(implementation)

  • Selector(typedef struct objc_selector *SEL):用于在运行时中表示一个方法的名称。一个方法选择器是一个C字符串,它是在Objective-C运行时被注册的。选择器由编译器生成,并且在类被加载时由运行时自动做映射操作。

  • Method(typedef struct objc_method *Method):在类定义中表示方法的类型

  • Implementation(typedef id (*IMP)(id, SEL, …)):这是一个指针类型,指向方法实现函数的开始位置。这个函数使用为当前CPU架构实现的标准C调用规范。每一个参数是指向对象自身的指针(self),第二个参数是方法选择器。然后是方法的实际参数。

理解,一个类维护一个运行时可接收的消息分发表,分发表中的每个入口是一个方法method,其中可以是一个特定名称,即选择器SEL,其对应一个实现IMP。即指向底层C函数的指针。

还要注意几点

  • 总是调用方法的原始实现,不调用原始方法,很有可能影响到程序的其他部分
  • 给自定义的方法加前缀,避免方法名冲突
  • 理解工作原理
  • 小心操作,万一版本一改就??了??了

 

以上是关于runtime 第四部分method swizzling的主要内容,如果未能解决你的问题,请参考以下文章

iOS runtime探究: 从runtiem开始实践Category添加属性与黑魔法method swizzling

Objective-C Runtime 运行时之四:Method Swizzling(转载)

Objective-C Runtime 运行时之四:Method Swizzling

iOS面试粮食Runtime—消息传递和转发机制Method Swizzling

iOS面试粮食Runtime—消息传递和转发机制Method Swizzling

iOS数据埋点统计方案(附Demo): 运行时Method Swizzling机制与AOP编程(面向切面编程)