读书人

[深入显出Cocoa]之消息(二)-详解动态

发布时间: 2012-11-23 22:54:33 作者: rapoo

[深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)

[深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)

罗朝辉 (http://blog.csdn.net/kesalin/)

本文遵循“署名-非商业用途-保持一致”创作公用协议 序言

如果我们在 Objective C 中向一个对象发送它无法处理的消息,会出现什么情况呢?根据前文《深入浅出Cocoa之消息》的介绍,我们知道发送消息是通过 objc_send(id, SEL, ...) 来实现的,它会首先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 对应的 IMP;如果没有找到且实现了动态方法决议机制就会进行决议,如果没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。也就是说如果同时提供了动态方法决议和消息转发,那么动态方法决议先于消息转发,只有当动态方法决议依然无法正确决议 selector 的实现,才会尝试进行消息转发。在前文中,我并没有详细讲解动态方法决议,因此本文将详细介绍之。

本文代码下载:点此下载

class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");

就能在运行期动态地为 name 这个 selector 添加实现:dynamicMethodIMP。class_addMethod 是运行时函数,所以需要导入头文件:objc/runtime.h。

再次编译运行前面的测试代码,输出如下:

//class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");

再次编译运行,此时输出:

//class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");

再次编译运行,此时输出正如前面所推断的那样:

  >> Bar() in Foo.  >> Instance resolving MissMethod  objc[1618]: +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found  >> forwardInvocation for selector MissMethod  >> MissMethod() called in Proxy.  >> Instance resolving _doZombieMe

进行了消息转发!而且编译器很善意地提示(见前面源码剖析):哎呀,你不能欺骗我嘛,你说添加了实现(返回YES),其实还是没有呀!然后编译器就无奈地去看能不能消息转发了。当然如果把返回值修改为 NO 就不会有该警告出现,其他的输出不变。

五,总结

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

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

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

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

3,其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会 crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;

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

六,引用

官方运行时源代码:http://www.opensource.apple.com/source/objc4/objc4-532/runtime/

Objective-C Runtime Programming Guide

深入浅出Cocoa之消息

深入浅出Cocoa之类与对象


读书人网 >移动开发

热点推荐