Objective-C Runtime 解读 (一)
本文主要基本解读关于Runtime相关的知识, 主要针对Runtime源码, OC中的类和对象进行基本的解释, 这个也是基于本人对Runtime源码分析和看了官方文档后的一点体会.
Runtime是什么?
下面是官方文档给出的解释:
The Objective-C language defers as many decisions as it can from compile time and link time to runtime. Whenever possible, it does things dynamically. This means that the language requires not just a compiler, but also a runtime system to execute the compiled code. The runtime system acts as a kind of operating system for the Objective-C language; it’s what makes the language work.
大致的意思就是: OC是一门动态的语言, 将编译和链接的时间推迟到了运行时, 这也说明OC提供了运行时的系统, 让我们在运行时做更多的事情, 因此, 运行时系统对OC是非常重要的, 可以说, runtime让OC能够更好地运行.
简单的说, 这也跟OC语言本省的特点有关, 因为OC是一门动态语言, 需要一个运行时库来支持OC的动态性, 因此, 理解runtime机制能够有助于我们对OC的理解和学习.
Runtime术语
这里简单提一下Runtime Versions and Platforms, 主要就是Legacy and Modern Versions, 针对这两个版本, 官网给出了具体的说明:
The most notable new feature is that instance variables in the modern runtime are “non-fragile”:
In the legacy runtime, if you change the layout of instance variables in a class, you must recompile classes that inherit from it.
In the modern runtime, if you change the layout of instance variables in a class, you do not have to recompile classes that inherit from it.
现在, 我们使用的都是modern runtime, 这个是跟随Objective - 2.0一起到来的, 现在的iPhone设备和64位的OS X系统都是使用的这个版本.
Runtime中的objc_class
在OC中我们最不陌生的就是NSObject了, 下面是NSObject的定义
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
看到这里我们就可以知道, 其实NSObject中最重要的信息也就是这个isa了,下面是runtime中给出的Class的定义:
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 *` */
这里我们再次看到了isa, 其实OC语言的动态性跟这个isa是分不开的, 下面对objc_class中比较关键的字段进行介绍:
1.isa:简单点说, isa指针也就是存储了该类的类型信息, 关于isa的具体指向, 下面这张图可以很好地解释:
这里需要特别注意的就是meta - class的概念, 在Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类), 简单点说, meta-class是一个类对象的类。
当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。
meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。
这就是像我们平常使用的”-” 和 “+”号方法一样, 其实二者的存储和查找方式是不太一样, 个人觉得, meta - class可能就是用来解决类方法的调用解析的.
2.cache: 第二个需要特别注意的就是这个擦cache, 我们都知道, OC采用的是动态的消息派发, 也就是运行时会有大量的消息发送和解析, 这样来说, 其实会很大程度上降低执行的效率, 那么cache其实就很好的弥补了这一点.
当我们像某个对象发送消息时, 一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
个人感觉, cache的设计也是objc_class这个结构体的一个闪光点.
3.superClass: 指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL。这也是实现动态消息解析的基础.
类与对象操作函数
下面简单介绍几个实用的操作函数:
1.类名
// 获取类的类名
const char * class_getName ( Class cls );
2.父类(super_class)和元类(meta-class)
// 获取类的父类
Class class_getSuperclass ( Class cls );
// 判断给定的Class是否是一个元类
BOOL class_isMetaClass ( Class cls );
3.成员变量(ivars)及属性
// 获取类中指定名称实例成员变量的信息
Ivar class_getInstanceVariable ( Class cls, const char *name );
// 获取类成员变量的信息
Ivar class_getClassVariable ( Class cls, const char *name );
// 添加成员变量
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
// 获取整个成员变量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
4.方法(methodLists)
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
// 获取实例方法
Method class_getInstanceMethod ( Class cls, SEL name );
// 获取类方法
Method class_getClassMethod ( Class cls, SEL name );
// 获取所有方法的数组
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
// 替代方法的实现
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
// 返回方法的具体实现
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
// 类实例是否响应指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
还有一些具体的函数, 大家可以查看源代码.
小结
本文主要介绍了runtime运行时中的一些数据结构, 包括一些基本的操作函数, 希望对理解runtime机制有所帮助.
参考
Objective-C Runtime Programming Guide
Objective-C Runtime 运行时之一:类与对象
理解 Objective-C Runtime