标签:编号 inter com logs 方法调用 添加 mil blog 方法区
-.runtime简介
在编译阶段,OC可以调用任何函数,即使这事函数并未实现,只要声明过就不会报错;
在编译阶段,C语言调用为实现的函数就会报错。
二、runtime作用
任何方法的调用本质,就是发送一个消息,用runtime发送消息。OC底层实现通过runtime实现。
解决:运行时方法中参数不提醒的问题
xcode6 之前,苹果运行使用objc_msgSend 是有参数提示的,之后就没有了。苹果不推荐我们使用runtime。如果方法,看:http://www.cnblogs.com/lyz0925/p/7365058.html。
简单代码如下:
//----runtime消息机制 //id self : 类名 //SEL op
//...:表示该方法需要,传入对应的参数。 //objc_msgSend(<#id self#>, <#SEL op, ...#>) id object = objc_msgSend([NSObject class], @selector(alloc)); objc_msgSend(object, @selector(init)); NSLog(@"---%@----", object);
以上的代码,类似于[[NSObject alloc] init] 的功能。
clang -rewrite-objc 文件名--使用编译器
runtime:方法都是有前缀的,谁的事情谁开头,例如-消息机制 用objc_msgSend 开头一样。
需要用到runtime的消息机制大致有:可以帮我们调用私有方法,另外就是装逼用,不要为了用runtime而用,而是再必要的时候才用。
如果消息机制调用了多个参数的话,如下代码:
//步骤:1.创建一个person类,2.声明一个run带NSInter类型的方法,3.实现该方法。之后再调用 Person *pers = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc")); objc_msgSend(pers, sel_registerName("init")); objc_msgSend(pers, @selector(run:), 30); //30 就是runtime需要传入的参数
方法调用流程:--面试
例如:如果调用person类上的eat方法? 对象方法:类对象的方法列表, 类方法:元类中查找方法
1.通过isa去对应的类中寻找对应的类方法
2.把方法名转成方法编号(注册方法编号--用编号可以快速的找到它)
3.根据方法编号去查找对应方法
4.找到只是最终函数实现地址,根据地址去方法区调用应对函数
内存5大区:栈 堆 静态区 常量区 方法区
栈:不需要手动管理内存,自动管理
2.交换方法(只要想修改系统方法实现时使用)
来个需求吧:每次UIImage用系统方法加载图片时,告诉我是否图片加载成功。
常规的方法,就是:
//判读图片是否赋值成功 UIImage *image = [UIImage imageNamed:@"111.png"]; if (image == nil) { NSLog(@"---图片赋值失败------"); }else { NSLog(@"---图片赋值成功------"); }
弊端:每次都要这么判断,太麻烦;
另外一种方法就是,自定义一个继承UIImage的类YZImage,然后重写imageNamed:的方法:
//重写方法:想给系统的方法添加额外功能 + (UIImage *)imageNamed:(NSString *)name { UIImage *image = [super imageNamed:name]; if (image) { NSLog(@"success"); }else { NSLog(@"fail"); } return image; }
弊端:每次使用,都需要导入自定义的头文件;如果是突然修改,项目大了,不太好替换。
因此,用运行时来实现这个需求是最好的选择!--给添加分类,用运行时交换方法
注意:在分类中,最好不要重写系统方法,一旦重写,把系统方法实现给覆盖了。
步骤:1.给系统的方法添加一个分类;
2.自己实现一个带有扩展功能的方法(命名时,给系统方法,加个前缀,例如yz_imageName:);
3.只交换一次。在load方法中,实现--load方法把内存加载进内存的时候调用,只会调用一次,另外需要在方法被调用之前,就替换系统的方法。 而initialize 会调用多次。
4.获取iamgeNamed方法、获取要替换的方法、交换方法:runtime
代码实现如下:
这里的代码是在UIImage 的自定义分类中实现的: + (void)load { Method imageName = class_getClassMethod(self, @selector(imageNamed:)); Method yz_imageName = class_getClassMethod(self, @selector(yz_imageName:)); //交换方法: method_exchangeImplementations(imageName, yz_imageName); //虽然走的imageName 但实际上是调用的yz_imageName //虽然走的yz_imageName 但实际上是调用的imageName } + (UIImage *)yz_imageName:(NSString *)name { // UIImage *image = [UIImage imageNamed:name]; --如果这里调用imageName就会有死循环的问题 UIImage *image = [UIImage yz_imageName:name]; if (image) { NSLog(@"success"); }else { NSLog(@"fail"); } return image; }
3.动态添加方法
在动态添加方法的时候,performSelector就是一个典型的例子。
为什么要动态添加方法?OC都是懒加载机制,只要一个方法实现了,就会马上添加到方法列表中。
注意:只要一个对象调用了一个未实现的方法就会调用resolveInstanceMethod:这个方法,进行处理。该方法的作用时,动态添加方法,处理未实现。
标签:编号 inter com logs 方法调用 添加 mil blog 方法区
原文地址:http://www.cnblogs.com/lyz0925/p/7401185.html