苹果不推荐我们使用runtime, 因此runtime是没有提示的。
打开提示将如下参数设置为no
我们通过2种调用类的实例方法的过程来研究
一下OC代码是如何转换成runtime代码的
@interface SWPerson : NSObject
- (void )eat;
@end
@implementation SWPerson
- (void )eat
{
NSLog(@"吃饭");
}
@end
OC代码
SWPerson *p = [[SWPerson alloc]init];
[p eat];
runtime代码
id p = objc_msgSend(objc_getClass("SWPerson"), sel_registerName("alloc"));
objc_msgSend(p, sel_registerName("init"));
objc_msgSend(p, sel_registerName("eat"));
OC代码实际上都会被编译器转换成 runtime代码执行。
runtime应用一 修改系统方法的实现
下面的方法将 imageNamed: 改成 imageWithNamed:执行。
这样可以做到监听系统的方法,然后在需要的时候 执行。
.h文件
#import <UIKit/UIKit.h>
@interface UIImage (exchange)
+ (UIImage *)imageWithNamed:(NSString *)name;
@end
.m文件
#import "UIImage+exchange.h"
#import <objc/message.h>
@implementation UIImage (exchange)
+(void)load{
Method systemMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method custormMethod = class_getClassMethod([UIImage class], @selector(imageWithNamed:));
method_exchangeImplementations(systemMethod, custormMethod);
}
+ (UIImage *)imageWithNamed:(NSString *)name{
UIImage *image = [UIImage imageWithNamed:name];
if (image == nil) {
NSLog(@"%@图片加载失败",name);
}
return image;
}
@end
原理解析
1 image对象找到该方法对应的编号;
2 通过方法的编号,找到方法列表中对应的方法
3 通过找到了方法列表中对应的方法,找到对应的方法的实现
4 在以上三点方法开始之前,我们通过load方法在OC的底层实现了对两个方法实现的交换
5 当外面用对象调用(imageNamed:)的方法的时候其实由于交换的方法实现的原因,该对象会去找(imageWithNamed:)方法的实现,当程序进入了(imageWithNamed:)方法的时候,在运行第二个(imageWithNamed:)方法的时候,其实是调用(imageNamed:)方法,然后再进行判断,如果输入的不是图片,那么自然的显示,加载失败.这就是runtime的交换方法.