一,消息传递机制
C是一个面向过程的语言,runtime的消息传递机制赋予了C面向对象的能力。
在OC中的方法是将消息接收者和消息内容用[]括起来,在运行的时候再对消息接收者发送该消息,具体如下:
objc_msgSend(id, SEL);
含有参数的是
objc_msgSend(id, SEL, arg1, arg2, ...);
例如
[obj doSomething]这个方法。
在编译的时候,编译器只是知道obj在调用doSomething这个方法,具体这个方法实现了没有也并不知道,因为并未真的在调用。
在运行的时候,才会通过转换成消息传递的方式去执行,具体如下:
objc_msgSend(obj, @selector(doSomething));
如果该方法只是声明,并未实现,就会进入动态方法解析。
二,动态方法解析
当方法没有实现,可以通过重载如下两个方法:
实例方法 +(BOOL)resolveInstanceMethod:(SEL)aSel
类方法 +(BOOL)resolveClassMethod:(SEL)aSel
然后通过class_addMethod去动态添加方法。
第三个参数是一个IMP函数指针。
最后一个参数涉及到Type Encoding,后面会解释。
如果这两个方法返回值是NO,将会进入消息转发。
三,消息转发
通过重写如下方法返回一个其他对象去重新制定新的消息接受者:
-(id)forwardingTargetForSelector:(SEL)aSel
如果该方法返回nil或者self,则会进入转发逻辑:
首先重写如下方法生成一个方法签名:
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSel
然后添加[NSMethodSignature signatureWithObjCTypes:""]去生成签名。
(这个唯一的参数是Type Encoding,下面会做解释。)
得到签名以后,系统会生成一个anInvocation对象,然后通过实现如下方法去进行转发:
-(void)forwardInvocation:(NSInvocation *)anInvocation
我们可以在该方法中让方法通过别的方式实现。
Type Encoding
用字符表示一个方法的返回类型和参数类型。
v表示void,@表示id,:表示SEL
因为OC的方法默认隐藏了两个参数,self和_cmd。
所以我们需要在返回类型的后面先写上隐藏参数self和_cmd对应的"@:"
例如
-(NSSthing *)name;这个方法的Type Encoding为"@@:"
其中第一个字符@表示返回一个对象,第二个字符@表示隐藏参数self,第三个字符:表示隐藏参数_cmd
-(void)setName:(NSSthing *)name;这个方法的Type Encoding为"v@:@"
第一个字符v表示void,第四个@表示参数name