runtime机制是iOS开发绕不过去的一个知识点。从网上查到一些资料,这里分享给大家。
runtime机制就是运行时机制,对象的生成和消息的发送都是是动态运行时生成的。我们之前所学的C 或者C++是编译性语言,也既是当你用C或者C++编写的程序编译时就直接被编译成了可令机器读懂的机器语言,当你的函数只声明而没有实现的话是会报错的,而OC的runtime程序不能直接编译成可令机器读懂的机器语言,而是当程序运行的时候,通过runtime机制把程序转为可令机器读懂的机器语言,函数只声明而不实现的话是不会报错的,他是一个C和汇编写的动态库。
runtime主要做两件事,
1.封装C语言的结构体和函数,让开发者在运行时创建、检查或者修改类,对象和方法等等;2.传递消息,找出方法的最终执行代码。
Obj从三中不同的层级上与runtime系统进行交互,分别是通过OC源代码,Foundation框架的NSObject类定义的方法,通过对runtime函数的直接调用
1、OC 源代码 :编写OC代码,程序在运行时,runtime会自动将OC转化成C语言代码
2、NSObject的方法
cocoa中大多数类都继承与NSObject类,也就自然继承了它的方法。最特殊的例外是NSProxy,它是个抽象超类,它实现了一些消息转发有关的方法,可以通过继承它来实现一个其他类的替身类或是虚拟出一个不存在的类。
有的NSObject中的方法起到了抽象接口的作用,比如description方法需要你重载它并为你定义的类提供描述内容。NSObject还有一些方法能在运行时获得类的信息,并检查一些特性,NSObject还有些方法能在运行时获得类的信息,并检查一些特性,比如class返回对象的类,isKindOfClass 和 isMemberOfClass用于检测对象是否在指定的类继承体系中,responseToSelected 检查对象能否响应指定的消息,confirmToProtocol 检查对象是否实现了指定协议类的方法,methodForSelector则返回指定方法实现的地址。
3.runtime函数: runtime函数系统是一个由一系列函数和数据结构组成,具有公共接口的动态共享库,许多函数允许你用纯C代码来重复实现Objc中同样的功能,虽然有一些方法构成了NSObject类的基础,但是你在写Objc代码时一般不会直接用到这些函数的除非是写一些objc与其他语言的桥接或是底层的debug工作。
objc_msgSend :
id objc_msgSend(id self, SEL op,...);
1.上面函数的二个参数类型是SEL,他是selector在OC中的表示类型,selector是方法选择器,可以理解区分方法的ID,而这个id的数据结构为SEL。其实它就是个映射到方法的C字符串,你可以用OC编译器命令@selector或则Runtime系统的sel_registName函数来获得一个SEL类型的方法选择器。不同类中相同名字的方法所对应的方法选择器是相同的,即使方法名字相同而变量类型不同也会导致他们具有相同的方法选择器,于是OBJ中方法命名有时会带上参数类型。
2.上面函数的第一个参数类型使id,它是一个指向实例类型的指针。typedef struct obj_object *id; struct objc_object{ Class isa OBJC_ISA_AVAILABILITY;};
isa: objc_object 结构体包含一个isa指针,根据isa指针就可以找到对象所属的类,objc_object中isa指针指向的类结构体称为class(也就是该对象所属的类)其中存放着普通成员变量与动态方法。
当我们想一个OC对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类,runtime库会在类的方法列表及父类的方法列表中去寻找与消息对用的selector指向的方法,找到后立即运行这个方法。
我们点开可以看到class其实是一个结构体,
typedef struct objc_class *Class;
struct objc_class {
Class isa; // 指向metaclass
Class super_class ; // 指向其父类
const char *name ; // 类名
long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取
long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量);
struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址
struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;
struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率;
struct objc_protocol_list *protocols; // 存储该类遵守的协议
}