Method Swizzle讲解

首先上图,图中是我们的类的结构关系图

有一个People基类,他有一个与生俱来的的本能:eat,另外有一个Kid,这个Kid继承了这个本能,并且他学会了新的技能:say,我们想在Kid eat的时候先通知willEat,然后在eat;在say的时候,先通知willSay,然后在say。下面我们来上代码。

 1 Class class = [self class];
 2         
 3         SEL originalSelector = @selector(eat:);
 4         SEL swizzledSelector = @selector(willEat:);
 5         
 6 //        SEL originalSelector = @selector(say:);
 7 //        SEL swizzledSelector = @selector(willSay:);
 8         
 9         Method originalMethod = class_getInstanceMethod(class, originalSelector);
10         Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
11         
12         BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
13         if (didAddMethod) {
14             // 添加成功,说明该类的originalSelector方法并不存在,可能是继承父类People而来的
15             NSLog(@"%@方法不存在,添加成功", NSStringFromSelector(originalSelector));
16             class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
17             NSLog(@"将%@的方法IMP替换成People的eat", NSStringFromSelector(swizzledSelector));
18         } else {
19             // 添加失败,说明该类的originalSelector方法已经存在
20             NSLog(@"%@方法已存在,添加失败", NSStringFromSelector(originalSelector));
21             method_exchangeImplementations(originalMethod, swizzledMethod);
22             NSLog(@"方法交换成功");
23         }

以上代码完成了我们的目标

1、首先我们先分析eat,eat是从People继承而来,所以,在Kid的method_list中找不到这个方法,这个时候调用 class_addMethod ,将会返回YES,并且我们看到了添加这个eat方法的时候,对应的IMP是willEat的IMP

即:eat —> willEat IMP, willEat —> willEat IMP

这个时候代码会执行 class_replaceMethod 操作,它的作用就是将SEL的IMP替换成指定的IMP,从代码中我们可以看出,我们将willEat的IMP替换成了People的eat的IMP

即:eat —> willEat IMP, willEat —> People eat IMP

- (void)willEat:(NSString *)food {
    NSLog(@"Kid will eat: %@", food);
    [self willEat:food];
}

这样一来,当调用[kid eat:@"orange"],输出如下:

1 Kid will eat: orange
2 People eat: orange

 

2、然后我们再来分析一下say,say是Kid自身的方法,所以在method_list中可以查到,这个时候会执行 method_exchangeImplementations ,它的作用是将两个SEL的IMP交换

交换前:say —> say IMP ,willSay —> willSay IMP

交换后:say —> willSay IMP ,willSay —> say IMP

这样一来,当调用[kid say: @"hello!"],输出如下:

1 Kid will say: hello!
2 Kid say: hello!

以上就是对Method Swizzle的分析,注意:class_addMethod:目的是解决当前交换的原始方法,是继承自父类的方法,而自身的method_list中不存在,此时如果调用method_exchangeImplementations交换方法,将会失败。

 

posted @ 2019-12-26 17:40  zbblogs  阅读(682)  评论(0编辑  收藏  举报