[receiver message] 的理解

来源:互联网 发布:tomcat线程池优化 编辑:程序博客网 时间:2024/05/22 16:23

前言

[receiver message]不是一个简简单单的方法调用。因为这只是在编译阶段确定了要向接收者发送message这条消息,而receive将要如何响应这条消息,那就要看运行时发生的情况来决定了。

如果消息的接收者能够找到对应的selector,那么就相当于直接执行了接收者这个对象的特定方法;否则,消息要么被转发,或是临时向接收者动态添加这个selector对应的实现内容,要么就干脆玩完崩溃掉。

要更好的理解这个过程,先了解一下运行时

Objc Runtime

使得C具有了面向对象能力,在程序运行时创建,检查,修改类、对象和它们的方法。可以使用runtime的一系列方法实现。

/usr/include/objc/runtime.h

类的结构

struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;#if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;    const char *name                                         OBJC2_UNAVAILABLE;    long version                                             OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;    long instance_size                                       OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */
  struct objc_class {    Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,r       untime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object    #if !__OBJC2__    Class super_class OBJC2_UNAVAILABLE; // 父类    const char *name OBJC2_UNAVAILABLE; // 类名    long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0    long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识    long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小    struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表    struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表    struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在method       Lists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。    struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表    #endif    } OBJC2_UNAVAILABLE;

OC中一个类的对象实例的数据结构

(/usr/include/objc/objc.h)
/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;/// Represents an instance of a class.struct objc_object {    Class isa  OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;#endif/// An opaque type that represents a method selector.typedef struct objc_selector *SEL;/// A pointer to the function of a method implementation. #if !OBJC_OLD_DISPATCH_PROTOTYPEStypedef void (*IMP)(void /* id, SEL, ... */ ); #elsetypedef id (*IMP)(id, SEL, ...); #endif

向object发送消息时,Runtime库会根据object的isa指针找到这个实例object所属于的类,然后在类的方法列表以及父类方法列表寻找对应的方法运行。id是一个objc_object结构类型的指针,这个类型的对象能够转换成任何一种对象。

objc_msgSend函数

消息发送步骤:

1、检测这个 selector 是不是要忽略的。比如 Mac OS X 开发,有了垃圾回收就不理会 retain,release 这些函数了。
2、检测这个 target 是不是 nil 对象。ObjC 的特性是允许对一个 nil 对象执行任何一个方法不会 Crash,因为会被忽略掉。
3、如果上面两个都过了,那就开始查找这个类的 IMP,先从 cache 里面找,完了找得到就跳到对应的函数去执行。
4、如果 cache 找不到就找一下方法分发表。
5、如果分发表找不到就到超类的分发表去找,一直找,直到找到NSObject类为止。
6、如果还找不到就要开始进入动态方法解析了。

后面还有:
动态方法解析resolveThisMethodDynamically
消息转发forwardingTargetForSelector

原创粉丝点击