runtime源码解读--数据结构

以下所有源码都是基于objc-2.0

1.类和对象

@interface NSObject  {
    Class isa  OBJC_ISA_AVAILABILITY;
}

typedef struct objc_class *Class;
typedef struct objc_object *id;

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();
    }
    ...
}

struct objc_object {
private:
    isa_t isa;
    ...
};

union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
    ...
    };

类大部分的数据存放在bits.data()里,看看class_rw_t

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    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,这个指针类型是常量,说明在编译器就决定了。这个结构里也有属性、协议、方法列表,和上面的比较起来,就是这里是在编译器生成的,上面的是在运行时动态生成的。

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    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;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};

参考链接:
深入解析 ObjC 中方法的结构

2. method SEL IMP

每个class都有个method列表,数据结构如下

struct method_t {
    SEL name;
    const char *types;
    IMP imp;
    ...
};

数据结构

typedef struct objc_selector *SEL;

但是源码里没有objc_selector的定义,通过查阅资料,SEL在不同编译环境定义不同,可以找到GNU环境下的定义

struct objc_selector
{
  void *sel_id;
  const char *sel_types;
};
//include/onx/runtime/[selector.h]

所以我猜测SEL只是保存了函数的标签。看下IMP的定义

#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id (*IMP)(id, SEL, ...); 
#endif

IMP是函数指针,指向了真正的函数实现。

你可能感兴趣的:(runtime源码解读--数据结构)