深入理解Objective-C的Runtime机制-Runtime数据结构

摘要:Objective-C是基于C加入了面向对象特性和消息转发机制的动态语言,除编译器之外,还需用Runtime系统来动态创建类和对象,进行消息发送和转发。

   Objective-C是基于C语言加入了面向对象特性和消息转发机制的动态语言,这意味着它不仅需要一个编译器,还需要Runtime系统来动态创建类和对象,进行消息

 发送和转发。下面通过分析Apple开源的Runtime代码(objc4-646.tar)来深入理解Objective-C的Runtime机制。

Runtime数据结构

  在Objective-C中,使用[receiver message]语法并不会马上执行receiver对象的message方法的代码,而是向receiver发送一条message消息,这条消息可能由receiver来处理,也可能由转发给其他对象来处理,也有可能假装没有接收到这条消息而没有处理。其实[receiver message]被编译器转化为:

id objc_msgSend (id self, SEL op, ... );  // 本质还是一个C函数

下面从两个数据结构id和SEL来逐步分析和理解Runtime有哪些重要的数据结构。

SEL:

  SEL是函数objc_msgSend第二个参数的数据类型,表示方法选择器,按下面路径打开objc.h文件:

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.2.sdk/usr/include/objc/objc.h

/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

  其实它就是映射到方法的C字符串,你可以通过Objc编译器命令@selector()或者Runtime系统的sel_registerName函数来获取一个SEL类型的方法选择器。

  如果你知道selector对应的方法名是什么,可以通过NSString* NSStringFromSelector(SEL aSelector)方法将SEL转化为字符串,再用NSLog打印。

id:

  接下来看objc_msgSend第一个参数的数据类型id,id是通用类型指针,能够表示任何对象。按下面路径打开objc.h文件:

typedef struct objc_class *Class;

/// Represents an instance of a class.(代表一个OC类)
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.(代表一个OC实例)
typedef struct objc_object *id;

  id其实就是一个指向objc_object结构体指针,它包含一个Class isa成员,根据isa指针就可以顺藤摸瓜找到对象所属的类。

注意:根据Apple的官方文档Key-Value Observing Implementation Details提及,key-value observing是使用isa-swizzling的技术实现的,isa指针在运行时被修改,指向一个中间类而不是真正的类。所以,你不应该使用isa指针来确定类的关系,而是使用class方法来确定实例对象的类。

Class:

// objc.h
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

// 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 *` */
注意:OBJC2_UNAVAILABLE是一个Apple对Objc系统运行版本进行约束的宏定义,主要为了兼容非Objective-C 2.0的遗留版本,但我们仍能从中获取一些有用信息。
  • isa表示一个Class对象的Class,也就是Meta Class。在面向对象设计中,一切都是对象,Class在设计中本身也是一个对象。
  • super_class表示实例对象的父类。
  • name表示类名。
  • ivars表示多个成员变量,它指向objc_ivar_list结构体。在runtime.h可以看到定义:
    struct objc_ivar_list {
        int ivar_count                                           OBJC2_UNAVAILABLE;
    #ifdef __LP64__
        int space                                                OBJC2_UNAVAILABLE;
    #endif
        /* variable length structure */
        struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;
    }                                                            OBJC2_UNAVAILABLE;

    objc_ivar_list其实就是一个链表,存储多个objc_ivar,而objc_ivar结构体存储类的单个成员变量信息。

  • methodLists表示方法列表,它指向objc_method_list结构体的二级指针,可以动态修改*methodLists的值来添加成员方法,也是Category实现原理,同样也解释Category不能添加属性的原因。在runtime.h可以看到它的定义:
    struct objc_method_list {
        struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;
    
        int method_count                                         OBJC2_UNAVAILABLE;
    #ifdef __LP64__
        int space                                                OBJC2_UNAVAILABLE;
    #endif
        /* variable length structure */
        struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
    }                                                            OBJC2_UNAVAILABLE;

    同理,objc_method_list也是一个链表,存储多个objc_method,而objc_method结构体存储类的某个方法的信息。

  • cache用来缓存经常访问的方法,它指向objc_cache结构体,后面会重点讲到。
  • protocols表示类遵循哪些协议。

  其实Meta Class也是一个Class,那么它也跟其他Class一样有自己的isa和super_class指针,关系如下:

    

        Class isa and superclass relationship from Google

  上图实线是super_class指针,虚线是isa指针。有几个关键点需要解释以下:

    1. Root class (class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的superclass指向nil。
    2. 每个Class都有一个isa指针指向唯一的Meta class
    3. Root class(meta)的superclass指向Root class(class),也就是NSObject,形成一个回路。
    4. 每个Meta class的isa指针都指向Root class (meta)。

 

posted @ 2016-02-17 13:06  若离相惜  阅读(281)  评论(0)    收藏  举报