runtime: 称之为运行时,Xcode5开始,苹果建议使用runtime, runtime是OC的底层是实现,也就是说我们平时写的OC代码通过runtime形式都变成C语言代码去执行了。
例如:Person * p =[[Person alloc]init];最后转化成 Person * p = objc_msgSend([Person class], @selector(alloc), @selector(init)); -->最终转换成 Person * p = objc_msgSend(objc_msgSend(objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
验证方法,Xcode创建工程MAC OS --> command line tool -->创建一个Personl类 -->在main函数中创建一个person对象-->终端cd到main函数文件所在的文件目录 --> clang -rewrite-objc main.m --> main文件所在目录下面就会生成一个man.cpp文件,打开就会发现有一个段代码:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
}
return 0;
}
亦这就验证了上面的结论是正确的。
runtime的运用:
运用一:
利用runtime进行URLWithString的交换。
首先我们要清楚 一个类里面的方法load的调用是先与main函数和appdelegate里面的方法的。
load方法的解释:当这个文件被加载进来的时候就调用。
所以在自定义的NSURL分类的.m文件的load方法中进行操作:
+(void)load
{
Method URLWithStr = class_getClassMethod([NSURL class], @selector(URLWithString:));
Method AWURLWithStr = class_getClassMethod([NSURL class], @selector(AW_URLWithStr:));
//方法的交换!!!!
method_exchangeImplementations(URLWithStr, AWURLWithStr);
}
/如果你做了方法的交换!!一定记得!!注释!!
+(instancetype)AW_URLWithStr:(NSString *)str
{
//想怎么实现就怎么实现!!!
NSLog(@"来了");
NSURL * url = [NSURL AW_URLWithStr:str];
NSLog(@"come here");
if(url == nil){
NSLog(@"哥么这个url伪nil");
}
return url;
}
这样当我们在别的类中调用系统的URLWithString这个方法的时候,就相当于调用了自己自定义的AW_URLWithStr方法
运用二:
方法的懒加载:
当一个类被调用了一个没有实现的对象方法,就会自动执行方法 +(BOOL)resolveInstanceMethod:(SEL)sel
例如:Person类没有定义OC写的对象方法eat:,那么当在ViewController中调用eat方法时候,就会自动调用resolveInstanceMethod方法。
ViewController的.m文件中
Person * p = [Person new];
[p performSelector:@selector(eat)];
Person的.m文件中
//SEL 方法的一个编号!!
//发现这个类有一个实例方法没有实现!!
+(BOOL)resolveInstanceMethod:(SEL)sel{
//来到这里..并且返回对应的SEL!!
NSLog(@"%@",NSStringFromSelector(sel));
//动态添加方法
if (sel == @selector(eat)) {
/**
1.class 类
2.SEL 方法编号
3.IMP(Implementation)方法实现,其实它就是要你传入一个指针!!
4.types 类型
*/
class_addMethod([self class], sel,(IMP)eat, "v@:");
}
return [super resolveInstanceMethod:sel];
}
//隐式参数!! 1.方法所属的对象 2.方法的编号! 任何方法其实都有这两个隐式参数!
void eat(id obj, SEL _cmd){
NSLog(@"哥么吃了!!%@",obj);
}