runtime版本主要分为OBJC和OBJC2,OBJC是传说,OBJC2是苹果2006年发布的,目前最新的。分析的源码是objc4-750
Runtime的数据结构主要包括objc_object、objc_class、isa指针、method_t
objc_object和objc_class
OBJC
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
具体可看runtime.h源码
上面是objc_class原始结构,官方是推荐使用Class替代objc_class的。
下面我们看下OBJC2的objc_class结构
OBJC2的objc_class结构
//objc_class 部分
typedef struct objc_class *Class;
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();
}
//...more
}
//objc-object部分
typedef struct objc_object *id;
struct objc_object {
private:
isa_t isa;
}
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
}
//Object
@interface Object {
Class isa;
}
//NSObject
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
具体可看objc-private.h
从上面源码可以看出:
Objective-C 对象都是 C 语言结构体实现的,objc_object结构体中包含一个isa_t类型的共用体。
平时我们使用的id类型,就是在Runtime中定义的objc_object类型。可以看出objc_object中包含isa_t共用体。
从继承关系,我们也可以看出Objective-C中类也是一个对象。
Cache_t
- 用于快速查找方法执行函数
- 是可增量扩展的哈希表结构。提高查找效率
- 是局部性原理的最佳应用。把使用率最高的方法放到cache_t中。
class_data_bits_t
主要是对class_rw_t的封装。
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_rw_t这里,以及只读信息class_ro_t。
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;
}
存储类在编译期就已经确定的属性、方法、协议。
类在内存中的位置是在编译期间决定的,在之后修改代码,也不会改变内存中的位置。
类的方法、属性以及协议在编译期间存放到了“错误”的位置,直到 realizeClass 执行之后,才放到了 class_rw_t 指向的只读区域 class_ro_t,这样我们即可以在运行时为 class_rw_t 添加方法,也不会影响类的只读结构。
在 class_ro_t 中的属性在运行期间就不能改变了,再添加方法时,会修改 class_rw_t 中的 methods 列表,而不是 class_ro_t 中的 baseMethods。
isa
从上面objc_class的结构可以看到,object和NSObject都包含isa指针。
isa指针的作用:
- 当调用一个对象的实例方法时,会通过isa找到相应的类,然后在该- 类的class_data_bits_t中查找方法。同时,每一个 objc_class 也有一个指向自己的父类的指针 super_class 用来查找继承的方法。
- 当调用类方法时,类对象的isa指针指向的是元类对象。(引入元类对象可以使实例方法和类方法的调用机制相同。)
简单地说:
实例方法调用时,通过对象的 isa 在类中获取方法的实现
类方法调用时,通过类的 isa 在元类中获取方法的实现
下面,我们可以看下对象、类、元类之间的关系:
类对象和元类对象都是objc_class数据结构的,objc_class继承自objc_object,都有isa指针。因此,实例对象可以通过isa指针找到类对象,类对象可以通过isa指针找到元类对象。
- Root class (class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的superclass指向nil。
- 每个Class都有一个isa指针指向唯一的Meta class
- Root class(meta)的superclass指向Root class(class),也就是NSObject,形成一个回路。
- 每个Meta class的isa指针都指向Root class (meta)。
类对象和元类对象的区别?
- 类对象存储实例方法列表等信息
- 元类对象存储类方法列表等信息
调用一个类方法,如果没有它的实现,但是有同名实例方法的实现,会不会崩溃,或者产生实际调用?
根据上面的关系图,会产生实际调用,根元类对象找不到对应的方法时,会去根类对象(即NSObject)中查找。
下面代码输出什么?
@implementation Son : Father
- (id)init
{
self = [super init];
if (self)
{
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
都是Son
self和super的区别:
self是类的一个隐藏参数,每个方法的实现的第一个参数即为self。
super并不是隐藏参数,它实际上只是一个”编译器标示符”,它负责告诉编译器,当调用方法时,去调用父类的方法,而不是本类中的方法。
在调用[super class]的时候,runtime会去调用objc_msgSendSuper方法,而不是objc_msgSend,也不是[super_class class]。
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
#else
__unsafe_unretained _Nonnull Class super_class;
#endif
/* super_class is the first class to search */
};
objc_msgSendSuper是去父类的方法列表中查找selector,找到后以receiver去调用父类中的selector。因此最后的调用者receiver就是self。