OC Runtime(5)之Method Swizzling

2014/4/2 posted in  iOS

Method的几个概念

  • Method包含方法名Selector、函数地址IMP、参数类型TypeEncoding
NSLog(@"    method name = %s", sel_getName(method_getName(method)));
NSLog(@"    method type encode = %s", method_getTypeEncoding(method));
NSLog(@"    NumberOfArguments = %d", method_getNumberOfArguments(method));
NSLog(@"    ReturnType = %s", method_copyReturnType(method));
2016-04-08 20:54:59.351 OCRuntime[54195:953880]     method name = setNumberProperty:
2016-04-08 20:54:59.352 OCRuntime[54195:953880]     method type encode = v24@0:8@16
2016-04-08 20:54:59.352 OCRuntime[54195:953880]     NumberOfArguments = 3
2016-04-08 20:54:59.352 OCRuntime[54195:953880]     ReturnType = v

动态修改Method的几个接口

// 设置或交换IMP
IMP method_setImplementation(Method m, IMP imp);
void method_exchangeImplementations(Method m1, Method m2);
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
                                 
// 如果原来没有这个方法,则直接添加Method,效果同class_addMethod
// 如果原来有,则替换掉原来的IMP,忽略参数类型
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
  • 例子:
+ (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);
        }
    });
}

参考