runtime 详解
本文结构:
- 简介
- runtime版本和平台
- 与runtime交互
- runtime术语
- 消息
- 动态方法解析
- 消息转发
- 健壮的实例变量
- 总结
1、简介
Cocoa的Objective-C语言可以在编译和链接的时候不知道类或者成员变量,只有在runtime(运行时)的时候才知道它们。runtime是iOS的一套底层API。它就像是Objective-C的操作系统,处理并执行Objective-C语言。比如:
//一个OC的方法调用
[receiver message];
//编译器会把它编译为:
objc_msgSend(receiver,message);
//假如消息中含有参数,会转化为如下形式:
[receiver message:arg...];
objc_msgSend(receiver,message,arg1,arg2,...);
runtime会在运行的时候知道这些经过编译之后的代码,然后去执行它。
2、runtime版本和平台
- logacy version: 运行在之前Objective-C 1.0的早期32位版本中。
- modern version:现在我们用的就是modern version,运行在iOS 和OSX 10.5之后的64位程序中。
3、与runtime交互
Objective-C 源代码
runtime会在后台自动的给你执行这些编译过的代码,我们只需写Objective-C代码即可。当然了我们也可以直接写runtime相关的代码,类似上面的例子中objc_msgSend()函数等。消息的执行会使用到编译器为实现动态语言创建的数据结构和函数,Objective-C中的类、方法和协议等在runtime中都是有一些结构体来定义。如objc_msgSend()函数已经参数 id 和 SEL。
NSObject 方法
Cocoa 中的大部分方法都是继承与NSObject,也继承了它的方法。唯一特殊的是NSProxy,它是个抽象的超类,它实现了一些消息转发的方法,可以继承它实现一些类的替身类或者是虚拟出一个不存在的类。
有的方法起到了抽象接口的左右,比如description方法需要你在重载它并为你提供的类添加描述信息。NSObject还有一些方法能获取到运行时类的信息,比如class:
返回对象的类;isKindOfClass:
和isMemberOfClassL:
则检查对象是否存在某个类继承体系中;respondsToSelector
则检查对象能否响应某方法;conformToProtocol
则检查是否实现了指定的协议;mothodForSelector
则返回方法实现的地址。
runtime的函数
runtime系统是一个有一些了函数和结构体组成,具有公共接口的动态库,头文件放在/usr/include/objc/
文件里面,通过包含头文件#import <objc/runtime.h>
就可以查看到这个头文件,里面的方法需要你通过编写C语言的方法来实现Objective-C的方法。在 Objective-C Runtime Reference中有对runtime函数的详细文档。
4、runtime术语
还是使用上面的objc_msgSend()方法吧,它的真身是
id objc_msgSend(id self,SEL op...)
id
objc_msgSend函数的第一个参数就是id,它是一个指向对象的指针。在/usr/include/objc/objc.h
中
typedef struct objc_object *id;
objc_object 是什么呢?
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
objc_object它是一个含有isa指针,通过它就可以找到对象所属的类。
注:isa指针在代码运行的时候并不总指向实例所属的类,所有不能考它来确定类型,可以通过-class
来确定。KVO的实现机理就是通过isa指针指向一个中间类而不是真实类型来实现。详情可看KVO的实现
SEL
objc_msgSend的第二个参数是SEL,它是selector在Objective-C中的表示。selector是一个方法选择器,可以理解为确保方法的ID,这个ID的数据结构是SEL
typedef struct objc_selector *SEL;
你可以用 Objc 编译器命令@selector()或者 Runtime 系统的sel_registerName函数来获得一个SEL类型的方法选择器。
Class
isa
是指针是因为Class 是一个指向objc_class结构体的指针:
typedef struct objc_class *Class;
而objc_class结构体里面包含许多信息
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
Class super_class ;
const char *name ;
long version ;
long info ;
long instance_size ;
struct objc_ivar_list *ivars ;
struct objc_method_list **methodLists ;
struct objc_cache *cache ;
struct objc_protocol_list *protocols ;
#endif
}
它有指向超类的super_class指针。其中 objc_ivar_list 是成员变量objc_ivar 列表;objc_method_list是objc_method方法列表。
// 成员变量列表
struct objc_ivar_list {
int ivar_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* v