runtime,简称运行时。最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数,编译完成之后直接顺序执行。OC的函数调用称为消息发送,属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(即使这个函数并未实现,只要申明过就不会报错,而C语言在编译阶段就会报错),只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
消息发送机制
OC语法中调用方法时,在运行时会变成objc_msgSend函数,我们可以通过运行时去直接调用方法,包括私有方法。
objc_msgSend函数首先会找到方法对应的方法实现,然后将消息接受者的对象以及方法中指定的参数传给所找到的方法实现,最后将方法实现的返回值作为函数的返回值返回。
首先要到build Settings关闭 strict checking,否则会报错。
交换方法
对象调用方法,先会到类中去搜寻方法列表,如果没有找到就去父类找,如果一直没有找到就会报出unrecognize selector错误。我们可以通过调用A方法,实现B方法。
注意class_getClassMethod和class_getInstanceMethod的区别,一个是获取类方法,一个是获取实例方法。
获取实例变量
获取类中的所有实例变量。
//类中实例变量的数量。函数返回一个数组,还有一个返回值通过传地址进去返回。 unsigned int ivarCount;
Ivar* ivarList = class_copyIvarList([Person class], &ivarCount); //遍历返回的实例变量数组
for (int i = 0; i < ivarCount; i++) {
//打印实例变量名
NSLog(@"%s",ivar_getName(ivarList[i]));
}
获取方法列表
获取类中的所有方法,包括属性的setter和getter方法。
unsigned int outCount;
Method *methodList = class_copyMethodList([Person class], &outCount); for(inti=0;i<outCount; i++){
SEL sel = method_getName(methodList[i]);
NSLog(@"%@",NSStringFromSelector(sel));
}
动态创建类,并添加实例变量和方法(KVO用该方法创建子类)
//分别为 继承父类的类名 ,类名
Class myClass = objc_allocateClassPair([NSObject class], "City", 0);
//添加实例变量,分别为变量所需类名,变量名,变量类型大小,变量类型编码
BOOL flag = class_addIvar([myClass class], "_name", sizeof(NSString *), 0, "@" );
if (flag) {
//如果添加成功,使用kvc为变量赋值
id newCity = [[myClass alloc]init];
[newCity setValue:@"深圳" forKey:@"_name"]; //读取变量值
NSLog(@"%@",[newCity valueForKey:@"_name"]);
}
//添加方法,方法所属类,方法选择器,方法实现,方法实现的类型编码 //类型编码要参考官方文档,v标识void返回类型 , //调用方法时,默认传入 调用者对象和方法选择器:对应 @: //第三个参数为NSString对象,所以用 @,综合为 v@:@
flag = class_addMethod([myClass class], @selector(aMethodSel:),(IMP)aMethodImp,"v@:"); //调用方法
id newCity = [[myClass alloc]init];
[newCity aMethodSel:@"添加方法"];
}
//方法实现,方法选择器最终找到方法实现并执行里面的代码 void aMethodImp(id self,SEL sel, NSString *name){
NSLog(@"%s methodname=%@",__func__,name); }
//方法选择器,类似于声明,里面的内容并不会执行 - (void)aMethodSel:(NSString *)name{
NSLog(@"%s selname=%@",__func__,name); }
关联对象
///分类中定义一个url属性,重写set,get
- (void)setUrl:(NSString *)url{
/**
* 关联属性的对象
属性的key值,这个值名字可以随便设,和取值时候保持一致就行 属性的value值
//内存管理策略,如copy,assign等
*/
objc_setAssociatedObject(self, "url", url, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)url{
//根据key值取出保存的value值
return objc_getAssociatedObject(self, "url");
}
}