OC 中方法调用是以消息传递实现的
[obj foo] 等同于 objc_msgSend(obj,@selector(foo))
类的底层构造
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指针
#if !__OBJC2__ Class
super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息
long instance_size OBJC2_UNAVAILABLE; // 类占据的内存大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行。如果在层层的寻找中,均未找到方法的实现,就会走消息转发机制,如果我们没有实现相应方法,就是会抛出
unrecognized selector sent to XXX
的异常,导致程序崩溃。
消息转发机制提供了三次机会去拯救程序
1、利用runtime重定义方法
voidrun (idself,SEL_cmd){
NSLog(@"person run");
}
//增加方法
+(BOOL)resolveInstanceMethod:(SEL)sel{
class_addMethod(self, sel, (IMP)run,"v@:");
return YES;
NSLog(@"person run");
}
//增加方法
+(BOOL)resolveInstanceMethod:(SEL)sel{
class_addMethod(self, sel, (IMP)run,"v@:");
return YES;
}
在resolveInstanceMethod中返回YES,程序就会认为我们已经重新实现了该方法,会重新调用该方法。
2、快速转发
//重定向方法
-(id)forwardingTargetForSelector:(SEL)aSelector{
return [[RunPersonalloc]init];
-(id)forwardingTargetForSelector:(SEL)aSelector{
return [[RunPersonalloc]init];
}
在该方法中,返回一个处理该消息的实例,这里不能返回自己的类对象,会死循环。
3、普通转发
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
return [NSMethodSignaturesignatureWithObjCTypes:"v@:"];
}
-(void)forwardInvocation:(NSInvocation*)anInvocation{
SEL sel = [anInvocation selector];
RunPerson* runPerson = [[RunPersonalloc]init];
if ([runPerson respondsToSelector:sel]) {
[anInvocation invokeWithTarget:runPerson];
}
-(void)forwardInvocation:(NSInvocation*)anInvocation{
SEL sel = [anInvocation selector];
RunPerson* runPerson = [[RunPersonalloc]init];
if ([runPerson respondsToSelector:sel]) {
[anInvocation invokeWithTarget:runPerson];
}
}