ios-动态添加方法,交换方法,重定向方法

  新建一个类Person,Person.h 不写代码,Person.m 有如下两个方法:

- (void)eat
{
    NSLog(@"xxx eat====");
}

【动态添加方法】

  尝试在 Person 类里添加一个 run 的实例方法。加上如下两个方法即可:

void run(id self, SEL sel, NSString *str) {
    NSLog(@"xxx run==%@", str);
}

// 只要调用了该类未实现的方法,就会来到这个方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    BOOL isSucess = NO;
    if (sel == @selector(run:)) {
        isSucess = class_addMethod(self, sel, run, "v@:@");
    }
    return isSucess;
}

  然后调用运行和打印如下:

Person *p = [Person new];
[p performSelector:@selector(run:) withObject:@"222xxxxxxxxxxx"]; // log: xxx run==222xxxxxxxxxxx

  在 ios调用私有方法 中有提到如何打印一个类下的方法 ,这里调用测试如下

    [self getMethods];
    
    Person *p = [Person new];
    [p performSelector:@selector(run:) withObject:@"222xxxxxxxxxxx"];
    
    [self getMethods];

  打印如下:

=============0
方法名= eat
参数类型= @
参数类型= :
返回类型值类型= v
xxx run==222xxxxxxxxxxx
=============0
方法名= run:
参数类型= @
参数类型= :
参数类型= @
返回类型值类型= v
=============1
方法名= eat
参数类型= @
参数类型= :
返回类型值类型= v

  从上面这个打印也可以看出,当没有调用这个方法时,打印 Person 类下方法只有eat一个;当调用了 run 方法后,这个方法就被添加到 Person 类的 methodlist 里了。

【交换方法】

  在 Person.m 中加一个 -sleep 方法

- (void)eat
{
    NSLog(@"xxx eat====");
}

- (void)sleep
{
    NSLog(@"xxx sleep===");
}

  可以在 Person 的 + load 方法中进行方法交换,因为一个类的 +load 方法在该类载入内存时就会开始调用。

+ (void)load
{
    Method m1 = class_getInstanceMethod(self, @selector(sleep));
    Method m2 = class_getInstanceMethod(self, @selector(eat));
    method_exchangeImplementations(m1, m2);
}

  调用 run: 方法和打印如下: (从打印可以发现,方法已经被替换了)

  Person *p = [Person new];

   [p performSelector:@selector(sleep)]; // log: xxx eat====

   [p performSelector:@selector(eat)];  // log: xxx sleep===

【重定向方法】

  在 Person.m 中 + load 方法如下: (意思是将sleep方法编号定向到eat方法的实现中)

+ (void)load
{
    Method m1 = class_getInstanceMethod(self, @selector(sleep));
    IMP imp = class_getMethodImplementation(self, @selector(eat));
    method_setImplementation(m1, imp);
}

  调用打印如下:(可以看到最终两个方法都进入eat)

    Person *p = [Person new];
    [p performSelector:@selector(sleep)]; // log: xxx eat====
    [p performSelector:@selector(eat)]; // log: xxx eat====

 

posted @ 2018-03-11 21:34  布尔-  阅读(1306)  评论(0编辑  收藏  举报