第12条:理解消息转发机制
1.消息转发机制的作用
对象在接受到无法解读的消息时,会在编译时报警告,运行时直接崩溃,此方法可以给对象和消息更多的机会来完成成功的调用
2.消息转发流程
(1)动态方法解析:
+(BOOL)resolveInstanceMethod:(SEL)sel // 实例方法
+(BOOL)resolveClassMethod:(SEL)sel // 类方法
- 下列代码演示了如何用“resolveInstanceMethod:”来实现@dynamic属性:
id autoDictionaryGetter(id self, SEL _cmd);
void autoDictionarySetter(id self, SEL _cmd, id value);
+ (BOOL)resolveInstanceMethod:(SEL)selector {
NSString *selectorString = NSStringFromSelector(selector);
if ( /* selector is from a @dynamic property */ ) {
if ([selectorString hasPrefix:@"set"]) {
class_addMethod(self,
selector,
(IMP)autoDictionarySetter,
"v@:@");
} else {
class_addMethod(self,
selector,
(IMP)autoDictionaryGetter,
"@@:");
}
return YES;
}
return [super resolveInstanceMethod:selector];
}
(2)备援接受者:运行期系统把消息转给其他接收者处理
- (id)forwardingTargetForSelector:(SEL)aSelector
{
class *other = [class new];
if ([other forwardingTargetForSelector:aSelector]) {
return other;
}else{
return [super forwardingTargetForSelector:aSelector];
}
}
(3)完整的消息转发:创建NSInvocation对象,把与尚未处理的那条消息有关的全部细节都封于其中。此对象包含选择子、目标target及参数。在触发NSInvocation对象时,消息派发系统会把消息指派给目标对象
- TestModel
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if(aSelector == @selector(testMethod))
{
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return nil;
}
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
if (anInvocation.selector == @selector(testMethod))
{
TestModelHelper1 *h1 = [[TestModelHelper1 alloc] init];
TestModelHelper2 *h2 = [[TestModelHelper2 alloc] init];
[anInvocation invokeWithTarget:h1];
[anInvocation invokeWithTarget:h2];
}
}
- TestModelHelper1
-(void)testMethod
{
NSLog(@"i am TestModelHelper1");
}
- TestModelHelper2
-(void)testMethod
{
NSLog(@"i am TestModelHelper2");
}
- 主调用类 : TestModel本身没有实现testMethod方法,但最终运行后,程序没有报错,且TestModelHelper1和TestModelHelper2的testMethod方法都被执行了
TestModel *model = [[TestModel alloc] init];
[model testMethod];
(4)消息未能处理:调用doesNotRecognizeSelector抛出异常