以下所有源码都是基于objc-2.0
1.类和对象
@interface NSObject <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是函数指针,指向了真正的函数实现。