您的位置:首页 > 移动开发 > Objective-C

objective-c中的消息响应机制

2016-04-08 19:52 232 查看
学习objective-c必然会接触消息操作,下面就消息的响应过程做一下分析和总结。

首先我们需要了解oc中的3种对象:实例对象;类对象;元类对象。

实例对象中保存着的主要结构有:isa指针,指向其类对象;实例成员变量;还有count引用计数等。

类对象中保存的主要数据结构:isa指针,指向该类的元类对象;super指针,指向父类的类对象;实例方法(’ – ‘ 开头的方法)调用地址映射表;

元类对象保存的主要数据结构:isa指针,指向NSObject的元类对象;super指针,指向父类的元类对象;类方法(’+’开头的方法)调用地址映射表;

当我们向一个对象(不一定是实例对象)发送消息时,首先将通过该对象的isa指针来到对应的另一个对象中(类对象或元类对象),注意:isa指针在整个消息响应的过程中会且仅会使用一次。先查找cache中是否已有对应的函数地址映射,有就直接使用。

注意:每个类对象(包括元类)都有一个独立的cache,用于保存继承链中和自身类中定义的方法。如果对应消息存在于cache中,那它仅稍微慢于函数调用。随着程序的运行所有cache中的方法将动态增长。

如果cache中没有,再查找对象内的dispatch table。若还是没有找到对应的响应函数,则沿着super指针在父类相应对象中进一步查找。

官方文档的示意图如下:



若到根类也没有找到的时候将会向对象发送forwardInvocation:消息,该消息默认调用doesNotRecognizeSelector:方法,该方法将生成一个错误消息表示异常发生。

forwardInvocation:消息定义在NSObject中,用户可以重定义该方法,当被发送不能处理的消息时,就可以将其转发给其他对象,或者自己执行错误处理。

下面举个简单的例子说明一下:

类A与类B的声明如下图



A继承了NSObject,而B继承了A。三个对象间的isa与super_ class指针的指向情况如下图。



此时我们可以做简单调用



注意:其中hash为NSObject的类方法,isProxy为NSObject的实例方法。

1.执行[a isProxy]时,消息首先通过isa指针从A的实例对象(a)到达A的类对象,发现A的类对象中并无对应的方法,于是通过super_class指针到达NSObject的类对象;在NSObject类对象中找到对应的方法并执行成功。

2.[b BClassMethod]之所以出错,因为发送消息首先到达B的类对象(通过isa),而B的类方法存储在B的元类对象中,通过super_class指针无法到达(需第二次通过isa指针,但是该指针在一次消息发送过程中能且只能使用一次)。

3.[B isProxy]的成功执行关键在于NSObject的元类对象的super_class指针指向了NSObject类对象。所以B的元类对象通过super_class找到了对应的实例方法。

4.[[[A class] class] class]:从原理上来说class是可以无限调用的,因为class方法返回isa指针指向的结构,而最终NSObject元类的isa指针指向自身。

总结:

实例对象可以调用自身及祖先的实例方法;但不能调用类方法,因为类方法在元类对象中,需第二次使用isa指针。

类对象可以调用自身及祖先中的类方法,同时还可以调用NSObject(根类)中定义的实例方法(因为所有元类的isa都指向NSObject的元类对象,而NSObject元类对象的super指针指向了NSObject的类对象,类对象中定义了实例方法)。

希望对大家有帮助,如若有误,敬请指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: