NSObject

参考:

NSObject 协议中定义的多种方法,是 OC 代码与 Runtime 发生交互的重要位置。

NSObject 基类

这个类与 NSObject 协议定义在了一个文件 Public Headers/NSObjects.h 中:

1
2
3
4
5
OBJC_ROOT_CLASS
OBJC_EXPORT
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

其中:

  • OBJC_ROOT_CLASS 是一个宏:

    1
    2
    3
    4
    5
    6
    7
    
    #if !defined(OBJC_ROOT_CLASS)
    #   if __has_attribute(objc_root_class)
    #       define OBJC_ROOT_CLASS __attribute__((objc_root_class))
    #   else
    #       define OBJC_ROOT_CLASS
    #   endif
    #endif
    

    它为 NSObject 这个类附加了 objc_root_class 这个属性,这是 GNU C 的特性,见:Attribute

  • OBJC_EXPORT 也是一个宏,它标记了这个类可以被任意外部位置访问到;

  • isa 是一个变量名,Class 是一个变量类型,OBJC_ISA_AVAILABILITY 也是一个宏,在 ObjC2 版本以后,isa 这个变量被标记为过期的属性,具体在 objc_object 中实现(下面详细解释)。

Classid 的定义在 Public Headers/objc.h 这个文件中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#if !OBJC_TYPES_DEFINED
/// 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

objc_classClass

这个类是所有Objective-C 类的夫类

在 Objc2 之前,该类的定义在 Public Headers/runtime.h 中,参考意义不大就不列举了,就是一个简单的字段组合。在 2006 年苹果公司发布 Objcive-C 2.0 之后,该类的定义在 Public Headers/objc-runtime-new.h 这个文件中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
		
  	class_rw_t *data() {
      	return bits.data();
    }
  	void setData(clas_rw_t *newData) {
      	bits.setData(newData);
    }
		// 此处有省略一些类方法...
}
  • superclass 是用于指向夫类的指针(NSObject 中也有一个同名的类方法);
  • cache 是方法缓存;
  • class_data_bits_t 是一个封装了比特位的类,bits 是这个类对应实例的方法链表。

这个类主要封装了与面向对象相关的方法,比如继承、哈希化等。

objc_objectid

这个类是包括 object_class 在内的所有实例对象的夫类

它定义在了文件 Project Headers/objc-private.h,是一个不对外暴露的私有类(对外暴露为 id):

1
2
3
4
5
6
7
8
9
struct objc_object {
private:
    isa_t isa;
  	// 此处有省略一些类方法...
  
public:
  	Class ISA();
  	Class getIsa();
}

isa 这个变量是这个类最核心的功能,它用于指定实例实现的类。观察函数也会发现,它主要实现 dealloc / retain / release 等析构、初始化、内存管理相关的工作。

小结:MetaClass

由上面的分析我们得出一个重要的结论:Objective-C 中类也是一个对象,这个对象是单例模式。实际上这些单例模式的对象是在 main 函数执行之前,从 dyldruntime 这期间创建的。

既然 OC 类派生自 objc_object,它就一定有 isa 这个成员,那么 OC 类的 isa 指针应该指向哪里呢?

这就牵涉到 isa 最重要的作用:消息传递。这里简单介绍一下消息传递的流程:

  1. 当源代码向一个对象发送消息时,会首先查找这个这个对象的 isa 参数;
  2. isa 参数指向一个类,Runtime 查找这个类的方法链表中查找并执行这个方法;

因此为了使 Objective-C 中的类也可以同样接受消息,Objective-C 将类方法分离了出去,称作元类(即 Meta Class)。Instance、Class、Meta-Class 三者的关系大致如下图:

../InstanceClassMetaclass.png

其中的 superclass 为 nil 的 Root class 即为 NSObjectNSObject 本质是 objc_class 这个类的单例。

isa_t

之前也提到了,在 Objective-C 中比较核心的 isa,它的类型为 isa_t。它的实现如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
  
#if defined(ISA_BITFIELD)
  	struct {
      	ISA_BITFIELD;
    };
#endif
		// 下面分别为 __arm64__ 与 __x86_64__ 定义了两个文件...
}

class_data_bits_t

objc_class 的一个成员的类型为 class_data_bits_t,它的声明如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
struct class_data_bits_t {
    // Values are the FAST_ flags above.
    uintptr_t bits;
private:
  	// 一些成员方法...
public:
  	class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    void setData(class_rw_t *newData)
    {
        assert(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
        // Set during realization or construction only. No locking needed.
        bits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
    }
		// 一些成员方法...
}

这个结构体只有一个 64 位的成员变量 bits。而它最重要的两个类方法也列举了出来:datasetData

bits 的内存布局可以用下面的示意图表示:

../class_data_bits_t.bits-mmlayout.png

  • is_swift:指示持有它的 objc_class 是不是一个 swift 语言的类;
  • has_default_rr:指示持有它的 objc_class 有没有默认实现 retain/release/autorelease 等方法;

class_rw_tclass_ro_t

一个 objc_class 类中的属性、方法还有遵循的协议信息都保存在了 class_rw_t 中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
struct class_rw_t {
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;

    Class firstSubclass;
    Class nextSiblingClass;
};

其中还有一个类型为 class_ro_t 指向常量的指针 ro,其中存储了当前类在编译期就已经确定的属性、方法以及遵循的协议

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
    uint32_t reserved;

    const uint8_t * ivarLayout;

    const char * name;
    method_list_t * baseMethodList;		// 持有这个类的 实例方法列表
    protocol_list_t * baseProtocols;	// 持有这个类的 实例协议列表
    const ivar_list_t * ivars;				// 持有这个类的 实例变量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
};
  • 在编译之后,class_data_bits_t.data 直接指向 class_ro_t

    也就是说 class_ro_t 是编译时产生的

  • 在 Runtime 加载了对应的 objc_class 之后,class_data_bits_t.dataclass_ro_t 的指向关系中插入了 class_rw_t 这个类,

    也就是说 class_rw_t 是运行时产生的

iva_t && method_t && protocol_t

class_rw_tclass_ro_t 两个类最要的三个成员变量:实例方法列表、实例协议列表、实例变量列表。

这三个列表都是三个基本类型的列表:

  1. ivar_t 表示的是一个实例变量,其关键字段是 字段起始位置的相对地址字段名称字段类型

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    struct ivar_t {
        int32_t *offset;
        const char *name;
        const char *type;
        // alignment is sometimes -1; use alignment() instead
        uint32_t alignment_raw;
        uint32_t size;
    
        uint32_t alignment() const {
            if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
            return 1 << alignment_raw;
        }
    };
    
  2. method_t 是表示一个实例方法,其关键字段是 方法选择器方法名称方法实现 三个:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    struct method_t {
        SEL name;
        const char *types;
        IMP imp;
    
        struct SortBySELAddress :
            public std::binary_function<const method_t&,
                                        const method_t&, bool>
        {
            bool operator() (const method_t& lhs,
                             const method_t& rhs)
            { return lhs.name < rhs.name; }
        };
    };
    

    其中:

    1. IMP 的底层,实际上就是一个函数的地址,编译结果是 void * 类型;
    2. binary_function 是 c++ 的语言:binary_function
  3. protocol_t 是一个协议的类型,它的结构就比较复杂了:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    struct protocol_t : objc_object {
        const char *mangledName;
        struct protocol_list_t *protocols;
        method_list_t *instanceMethods;
        method_list_t *classMethods;
        method_list_t *optionalInstanceMethods;
        method_list_t *optionalClassMethods;
        property_list_t *instanceProperties;
        uint32_t size;   // sizeof(protocol_t)
        uint32_t flags;
        // Fields below this point are not always present on disk.
        const char **extendedMethodTypes;
        const char *_demangledName;
    
        const char *demangledName();
    
        const char *nameForLogging() {
            return demangledName();
        }
    
        bool isFixedUp() const;
        void setFixedUp();
    
        bool hasExtendedMethodTypesField() const {
            return size >= (offsetof(protocol_t, extendedMethodTypes) 
                            + sizeof(extendedMethodTypes));
        }
        bool hasExtendedMethodTypes() const {
            return hasExtendedMethodTypesField() && extendedMethodTypes;
        }
    };
    

总结:类派生图

上面列举的这些类,它们在代码中体现的派生结构,可以用下面的图表示:

../runtime-struct-summary.png