在OC中,函数的执行,本质是消息发送。
所有的函数调用转化为C函数即obj_msgSend(id,sel,param)
不同于其他语言,在对象中声明的方法可以不必非得实现,编译也能通过,虽然最后程序会崩溃。
unrecognized selector sent to instance xxxxx
当一个实例对象调调用方法时,首先会在自己的类对象的方法列表中查找对应的方法,没找到的话就通过父类继续查找。
只到查找到NSOBject类中,也没有发现相应的方法,此时就会触发消息转发机制。
说白了,消息转发机制就是系统给你拯救程序崩溃的机会,这样的机会一共有三次,如果这三次机会都没有把消息处理掉,程序才会崩溃。
第一次机会:通过NSObeject的实例方法:-(BOOL)resolveInstanceMethod:(SEL)sel
你只有在这个方法中,处理消息并且返回YES,那么消息转发过程就会终止,程序正常运行。处理过程如下:
NSString *selStr = NSStringFromSelector(sel);
if([selStr isEqualToString:@"yourMethodName"]) {
IMP imp =class_getMethodImplementation(self,@selector(replaceMethod));//替代实现的方法
class_addMethod(self, sel, imp,"v@:");//动态添加一个方法,来代替原来方法的实现
returnYES;
}else{
return [super resolveInstanceMethod:sel];
}
如果这个方法最终返回的是NO,那么第二次机会就登场了:NSObeject的实例方法:-(id)forwardingTargetForSelector:(SEL sel);
这个方法返回的是一个id类型,即任何类型。你可以理解为一个代理对象,当前对象没有实现的方法,交给其他类实现。
- (id)forwardingTargetForSelector:(SEL sel){
NSString *selStr = NSStringFromSelector(sel);
if([selStr isEqualToString:@"yourMethodName"]) {
return [DelegateObject new];//在DelegateObject类中实现对应的方法
}else{
return nil;
}
}
如果在这一步还是没有处理,那么就只剩最后一次机会了:NSObeject的实例方法:-(void)forwardInvocation:(NSInvocation *)anInvocation;
if(anInvocation.selector==@selector(sing)) {
DelegateObject*delegate =DelegateObject;
[anInvocation invokeWithTarget:delegate];//也是交给其他对象处理
}
在调用这个方法之前还要返回对应方法的编码类型,实现函数-(NSMethodSignature*)methodSignatureForSelector:(SEL)sel;
if(aSelector ==@selector(yourmethod)) {
return [NSMethodSignature signatureWithObjCTypes:"V@:@"];//V代表返回值为void,@代表消息接收对象,:代表选择子,@代表参数
}
return [super methodSignatureForSelector:aSelector];
以上就是OC消息转发机制了。虽然有这个机制的存在,但最好还是不要用到这个,养成的良好的编码习惯,在头文件中声明的函数要自己完成实现。