消息
在Objective-C中,消息是直到運(yùn)行的時(shí)候才和方法實(shí)現(xiàn)綁定的。消息機(jī)制的關(guān)鍵在于編譯器為類和對(duì)象生成的結(jié)構(gòu)。每個(gè)類的結(jié)構(gòu)中至少包括兩個(gè)基本元素:
(1) 指向父類的指針
(2)類的方法表。方法表將方法選標(biāo)和該類的方法實(shí)現(xiàn)的地址關(guān)聯(lián)起來。
消息框架如下

消息轉(zhuǎn)發(fā)
當(dāng)向someObject發(fā)送消息,但runtime system在當(dāng)前類和父類中都找不到對(duì)應(yīng)的方法實(shí)現(xiàn)時(shí)。runtime system并不會(huì)立即報(bào)錯(cuò)使程序崩潰,而是依次執(zhí)行下列步驟:

分別簡(jiǎn)述一下流程:
(1) 動(dòng)態(tài)方法解析 向當(dāng)前類發(fā)送 resolveInstanceMethod: 或者 resolveClassMethod: 消息,檢查是否動(dòng)態(tài)向該類添加了方法。
(2)快速消息轉(zhuǎn)發(fā) 檢查該類是否實(shí)現(xiàn)了forwardingTargetForSelector: 方法,若實(shí)現(xiàn)了則調(diào)用該方法。若該方法返回值對(duì)象非nil或非self,則向該返回對(duì)象重新發(fā)送消息。
(3)標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā) runtime發(fā)送methodSignatureForSelector:方法獲取Selector對(duì)應(yīng)的方法簽名。返回值非nil則通過forwardInvocation:轉(zhuǎn)發(fā)消息,返回值為nil則向當(dāng)前對(duì)象發(fā)送doesNotRecognizeSelector:消息,程序崩潰退出。
示例
示例界面如下

#pragma mark - event response
- (void)dynamicBtnClicked:(id)sender
{
self.dianDi86.name = @"DianDi86";
NSLog(@"%@",self.dianDi86.name);
}
- (void)fastForwardBtnClicked:(id)sender
{
[self.whiteHouse performSelector:@selector(setSex:) withObject:@"Boy"];
}
- (void)normalForwardBtnClicked:(id)sender
{
[self.audioA4L performSelector:@selector(setSex:) withObject:@"Boy"];
}
動(dòng)態(tài)方法解析
#import "People.h"
#include <objc/runtime.h>
void dynamicSetNameIMP(id self, SEL _cmd, NSString *name)
{
NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
if (((People*)self)->_name != name) {
((People*)self)->_name = [name copy];
}
}
NSString* dynamicNameIMP(id self, SEL _cmd)
{
NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
return ((People*)self)->_name;
}
@implementation People
@dynamic name;
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(setName:)) {
class_addMethod(self, sel, (IMP)dynamicSetNameIMP, "v@:@");
return YES;
} else if (sel == @selector(name)) {
class_addMethod(self, sel, (IMP)dynamicNameIMP, "@@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
點(diǎn)擊示例界面中的動(dòng)態(tài)方法解析console log 如下

快速消息轉(zhuǎn)發(fā)
- (id)forwardingTargetForSelector:(SEL)aSelector
{
// House 類需要將消息轉(zhuǎn)發(fā)給People
NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
if ([self.master respondsToSelector:aSelector]) {
return self.master;
}
return nil;
}
點(diǎn)擊示例界面中的快速消息轉(zhuǎn)發(fā)console log 如下

標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā)
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
{
NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
NSMethodSignature *sign = [super methodSignatureForSelector:aSelector];
if (sign == nil) {
sign = [self.master methodSignatureForSelector:aSelector];
}
return sign;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"%@ %@",self, NSStringFromSelector(_cmd));
SEL selector = [anInvocation selector];
if ([self.master respondsToSelector:selector]) {
[anInvocation invokeWithTarget:self.master];
}
}
點(diǎn)擊示例界面中的快速消息轉(zhuǎn)發(fā)console log 如下
