新建一个类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====