我们都知道oc是动态语言,所谓的动态语言就是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上变化的语言。因为它可以在程序执行过程中对类或者变量等等做操作,而不是代码写完了,程序就定型了。
runtime的所有知识基本都围绕两个中心(1)类的各个方面的动态配置(2)消息传递
要动态配置类就需要知道类的本质是什么,我们可以从里面看到类的定义:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class;//父类
const char *name;//类名
long version;//类的版本信息,默认为0
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}
OBJC2_UNAVAILABLE;
isa和super_class
不同的类中可以有相同的方法,同一个类中不可以有相同的方法,判断是不是同一个方法只和方法名有关系,和参数没关系。
比如说:
1
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{}
的方法名为
@selector(tableView:canEditRowAtIndexPath:)
可见方法名里面并没有体现参数的位置,所以是否是同一个方法取决于方法名是否相同,和参数没关系。
要找到方法首先要先确定是那个类。isa和super_class是找到实现函数的关键映射,决定找到存放在哪个类的方法实现。(isa用于自省确定所属类,super_class确定继承关系)。
实例对象的isa指针指向类,类的isa指针指向其元类(metaClass)。对象就是一个含isa指针的结构体。类存储实例对象的方法列表,元类存储类的方法列表,元类也是类对象。
当创建实例对象时,分配的内存包含一个objc_object数据结构,然后是类到父类直到根类NSObject的实例变量的数据。NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。
向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表由super_class指针找到父类的方法列表直至根类NSObject中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。
在正式学习runtime之前你需要知道的
属性概念
SEL:类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。
IMP:一个函数指针,保存了方法的地址
Method:方法的结构体,其中保存了方法的名字,实现和类型描述字符串
//在runtime.h里面我们可以看到定义
//Method 是一个方法结构体的指针
typedef struct objc_method *Method;
//方法的结构体包含了方法需要的信息
struct objc_method {
SEL method_name;
char *method_types;//方法返回值,和各个参数类型等的字符串描述
IMP method_imp;
}
//根据函数获取函数的SEL
@selector()
//获取函数指针SEL的函数名字符串
NSString *NSStringFromSelector(SEL aSelector);
//根据函数名获取函数指针
SEL NSSelectorFromString(NSString *aSelectorName);
//获取类Class的字符串描述
NSString *NSStringFromClass(Class aClass);
//根据类的字符串描述获取类Class
Class _Nullable NSClassFromString(NSString *aClassName);
//获取协议的字符串描述(协议名字)
NSString *NSStringFromProtocol(Protocol *proto)
//根据协议名字获取协议对象
Protocol * _Nullable NSProtocolFromString(NSString *namestr)
下面会用到的编码值
//下面对应的编码值可以在官方文档里面找到
//编码值 含意
//c 代表char类型
//i 代表int类型
//s 代表short类型
//l 代表long类型,在64位处理器上也是按照32位处理
//q 代表long long类型
//C 代表unsigned char类型
//I 代表unsigned int类型
//S 代表unsigned short类型
//L 代表unsigned long类型
//Q 代表unsigned long long类型
//f 代表float类型
//d 代表double类型
//B 代表C++中的bool或者C99中的_Bool
//v 代表void类型
//* 代表char *类型
//@ 代表对象类型
//# 代表类对象 (Class)
//: 代表方法selector (SEL)
//[array type] 代表array
//{name=type…} 代表结构体
//(name=type…) 代表union
//bnum A bit field of num bits
//^type A pointer to type
//? An unknown type (among other things, this code is used for function pointers)
//获取类名
//入参:类Class
//返回:类名char数组
const char *class_getName(Class cls)
//获取父类
//入参:类Class
//返回:类Class
Class class_getSuperclass(Class cls)
//获取实例大小(返回size_t)
//入参:实例的类Class
//返回:大小size_t
//深究请看这篇文章http://www.jianshu.com/p/df6b252fbaae
size_t class_getInstanceSize(Class cls)
//获取类中指定名称实例成员变量的信息
//入参:类Class,变量名
//返回:变量信息Ivar
//* 1.实例变量是指变量不是属性.例如某类有个属性为:username 那么它对应的实例变量为_username
//* 2.这个方法可以获取属性的变量,也可以获取私有变量(这点很重要)
//* 3.如果获取的变量为空,那么 ivar_getName和 ivar_getTypeEncoding 获取的值为空,那么[NSString stringWithUTF8String:ivar1Name] 执行崩溃
Ivar class_getInstanceVariable(Class cls, const char *name)
//类成员变量的信息
//入参:类Class,变量名char数组
//返回:Ivar
//* 1.目前没有找到关于Objective-C中类变量的信息,一般认为Objective-C不支持类变量。注意,返回的列表不包含父类的成员变量和属性。
Ivar class_getClassVariable(Class cls, const char *name)
//获取指定的属性
//入参:类Class,属性名char数组
//返回:属性objc_property_t
// * 1.属性不是变量,此方法只能获取属性
// * 2.如果属性不存在那么返回的结构体为0(可以参考下面的判断)
// * 3.属性不存在获取property_getName 和 property_getAttributes 会崩溃
objc_property_t class_getProperty(Class cls, const char *name)
//获取方法实现
//入参:类Class,方法名SEL
//返回:方法实现IMP
IMP class_getMethodImplementation(Class cls, SEL name)
//获取方法实现
//入参:类Class,方法名SEL
//返回:方法实现IMP
IMP class_getMethodImplementation_stret(Class cls, SEL name)
//获取类方法
//入参:类Class,方法名SEL
//返回:方法Method
Method class_getClassMethod(Class cls, SEL name)
企业级独立部署应用:知行办公http://zx.naton.cn
【总监】十二春秋之,3483099@qq.com;
【Master】zelo,616701261@qq.com;
【运营】运维艄公,897221533@qq.com;
【产品设计】流浪猫,364994559@qq.com;
【体验设计】兜兜,2435632247@qq.com;
【iOS】淘码小工,492395860@qq.com;iMcG33K,imcg33k@gmail.com;
【Android】人猿居士,1059604515@qq.com;思路的顿悟,1217022114@qq.com;
【java】首席工程师MR_W,feixue300@qq.com;
【测试】土镜问道,847071279@qq.com;
【数据】喜乐多,42151960@qq.com;
【安全】保密,你懂的。