首页 > 代码库 > 动态方法决议 和 消息转发

动态方法决议 和 消息转发

假设我们在 Objective C 中向一个对象发送它无法处理的消息,会出现什么情况呢?我们知道发送消息是通过 objc_send(id, SEL, ...) 来实现的,它会首先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 相应的 IMP;这个是须要对类对象的结构熟悉,不清楚的能够參考我的下一篇文章《object-c 类结构解析》假设没有找到且实现了动态方法决议机制就会进行决议,假设没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。也就是说假设同一时候提供了动态方法决议和消息转发,那么动态方法决议先于消息转发,仅仅有当动态方法决议依旧无法正确决议 selector 的实现,才会尝试进行消息转发。


1.  什么是动态方法决议

Objective C 提供了一种名为动态方法决议的手段,使得我们能够在执行时动态地为一个 selector 提供实现。我们仅仅要实现 +resolveInstanceMethod: 或 +resolveClassMethod: 方法,并在当中为指定的 selector  提供实现就可以(通过调用执行时函数 class_addMethod 来加入?)。这两个方法都是 NSObject 中的类方法,其原型为:

+ (BOOL)resolveClassMethod:(SEL)name;
+ (BOOL)resolveInstanceMethod:(SEL)name;

2.消息转发

实现下面这两个方法

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    SEL name = [anInvocation selector];
    NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
    
    Proxy * proxy = [[[Proxy alloc] init] autorelease];
    if ([proxy respondsToSelector:name]) {
        [anInvocation invokeWithTarget:proxy];
    }
    else {
        [super forwardInvocation:anInvocation];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Proxy instanceMethodSignatureForSelector:aSelector];
}

总结

从上面的演示样例演示能够看出,动态方法决议是先于消息转发的。

假设向一个 Objective C 对象对象发送它无法处理的消息(selector),那么编译器会依照例如以下次序进行处理:


1,首先看是否为该 selector 提供了动态方法决议机制,假设提供了则转到 2;假设没有提供则转到 3;

2,假设动态方法决议真正为该 selector 提供了实现,那么就调用该实现,完毕消息发送流程,消息转发就不会进行了;假设没有提供,则转到 3;

3,其次看是否为该 selector 提供了消息转发机制,假设提供了消息了则进行消息转发,此时,不管消息转发是如何实现的,程序均不会 crash。(由于消息调用的控制权全然交给消息转发机制处理,即使消息转发并没有做不论什么事情,执行也不会有错误,编译器更不会有错误提示。);假设没提供消息转发机制,则转到 4;

4,执行报错:无法识别的 selector,程序 crash;


參考:

http://www.cnblogs.com/kesalin/archive/2012/11/14/dynamic_method_resolve.html

http://www.cnblogs.com/biosli/p/NSObject_inherit_2.html