runtime的所有知识基本都是围绕两个中心:
1.类的各个方面的动态配置
动态创建类,动态地为类添加属性和方法,动态绑定,动态加载.
2.消息传递
调用方法时@selector(方法名)只是SEL指针,SEL指针只是方法编号,在运行时,才会根据SEL和id也就是调用方法的对象获得IMP指针,确定执行的方法.
类的本质(定义):
struct objc_class{
class isa OBJC_ISA_ACAILABILITY; *指向其类的isa指针
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; *协议链表
}
OC中类是由class类型来表示的,实际上它是一个指向objc_class的结构体
不同的类中可以有相同的方法,同一个类中不可以有相同的方法,判断是不是同一个方法只和方法名有关,与参数无关.
属性概念
SEL: 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是保存方法的编号.
IMP:一个函数指针,保存了方法的地址.
method:方法的结构体,其中保存了方法的名字,实现和类型描述字符串
每个继承于NSObject的类都能自动获得runtime的支持,在这样一个类中,有一个isa指针,指向该类定义的数据结构体,这个结构体是由编译器,编译时为类创建的,在这个结构体中包括了指向其父类类定义的指针以及Dispatch table, Dispatch table是一张SEL和IMP的对应表.
要找到方法首先要确定是哪个类,isa和super_class是找到实现函数的关键映射,决定找到存放在哪个类的方法实现(isa用于自省确定所在类,super_class确定继承关系)
过程:
同一个Object-C对象发送消息时,运行时会根据实例对象的isa指针找到这个实例对象所属的类,runtime库会在类的方法列表由super_class指针找到父类的方法列表直到根类NSObject中去寻找与消息对应的selector指向的方法,找到后即运行这个方法
继承层次中字类,父类,根类,以及其对应metaclass(元类)的isa与super_class直接的关系:
1. 类的实例对象的isa指向该类;该类的isa指向该类的metaclass
2.类的super_class指向其父类,若该类为根类则值为NULL;
3.metaclass的isa指向根metaclass,若该metaclass是根metaclass则指向自身.
4.metaclass的super_class指向父metaclass,若该metaclass是根metaclass则指向该metaclass对应的类.
方法的存储位置
每个类的方法列表都存储在类对象中,每个方法都有一个与之对应的SEL类型的对象,根据一个SEL对象,就可以找到方法的地址进而调用方法.
SEL类型的定义
typedef struct objc_selector *SEL;
IMP(implement)类型的定义
typedef id(* IMP) (id, SEL, ...);
IMP是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self指针)调用方法的SEL(方法名)以及不定个数的方法参数,并返回一个id;
IMP是消息最终调用的执行代码,是方法真正的实现代码
SEL和IMP其实就实现了多态,一个SEL指向不同的函数指针,完成了一个方法名在不同时候执行不同的函数体.
Q1:获取方法编号
@selector就是取类方法的编号
SEL methodId = @selector(func1);
SEL methodId2 = NSSelectorFromString(@“test”);
Q2:执行对应方法
[self performSelector: methodId withObject: nil];
Q3:通过编号获取方法
NSString *methodName = NSStringFromSelector(methodId);
Q4:IMP怎么获取和使用
IMP methodPoint = [self methodForSelector: methodId];
methodPoint() //使用
网友评论