首先创建一个Dog类,然后添加两个C语言方法。
//这是一个 C 语言的函数,它至少包含了 self 和 _cmd 两个参数(self 代表着函数本身,而 _cmd 则是一个 SEL 数据体,包含了具体的方法地址)
void eat(id self,SEL sel){
NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}
void run(id self,SEL sel , NSString *band){
NSLog(@"%@ %@ %@",self,NSStringFromSelector(sel),band);
}
然后在m文件中重写resolveInstanceMethod或者resolveClassMethod方法。看情况而定。
两个方法的区别在于需要添加的是静态方法还是实例方法。
+ (BOOL)resolveInstanceMethod:(SEL)sel
+ (BOOL)resolveClassMethod:(SEL)sel
在 Objective-C中,正常的调用方法是通过消息机制(message)来实现的,那么如果类中没有找到发送的消息方法,系统就会进入找不到该方法的处理流程中,如果在这个流程中,我们加入我们所需要的新方法,就能实现运行过程中的动态添加了。这个流程或者说机制,就是 Objective-C的 Message Forwarding 。
// 静态方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == NSSelectorFromString(@"eat")) {
// 注意:这里需要强转成IMP类型
class_addMethod(self, sel, (IMP)eat, "v@:");
return YES;
}
if (sel == @selector(run:)) {
class_addMethod(self, sel, (IMP)run, "v@:");
return YES;
}
// 先恢复, 不然会覆盖系统的方法
return [super resolveInstanceMethod:sel];
}
//动态方法
+ (BOOL)resolveClassMethod:(SEL)sel{
return [super resolveClassMethod:sel];
}
然后调用一下检查一下成果
Dog *dog = [[Dog alloc] init];
// 没有实现eat方法,可以通过performSelector调用,但是会报错。
// 动态添加方法仅仅是警告但是不会报错。已经已经runtime实现了这个方法。
[dog performSelector:@selector(eat)];
[dog performSelector:@selector(run:) withObject:@"跑起来"];
上面我们代码运行会有个警告。好尴尬。下面方法,可以去掉