runtime是什么
runtime,即运行时机制。
runtime是一套底层的纯C的API,是一个C语言库。
平时写的OC代码,最终都会转成runtime的C语言代码,runtime的幕后工作者。
比如:
在OC中:
[[Person alloc] init];
在runtime中:
objc_msgSend(objc_msgSend("Person","alloc"),"init");
runtime的应用
- 拦截系统的方法调用
- 把OC代码转换为运行时代码,探究底层,比如block的内部实现
- 字典转模型
- 在程序运行的状态中,动态创建一个类 (比如KVO底层的实现)
- 在程序运行的状态中,动态地为某个类添加属性/方法,修改属性值/方法(分类增加属性。
有人说分类不能增加属性,这是不准确的,分类可以增加属性,并且会自动生成声明,但不会自动生成get/set方法,这时就需要借助runtime来实现)
#import <Foundation/Foundation.h>
@interface NSObject (Ex)
@property (nonatomic, copy) NSString *name;
@end
#import "NSObject+Ex.h"
#import <objc/runtime.h>
char namekey;
@implementation NSObject (Ex)
//关联对象函数
// id object被关联的对象
// const void *key关联键
// id value 关联值
// objc_AssociationPolicy policy 关联策略
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, &namekey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, &namekey);
}
@end
- 遍历一个类的成员变量(属性)
相关方法和头文件
-
头文件
<objc/runtime.h>
<objc/message.h> -
方法
-
NSCoding(归档和解档)
-
字典转模型(利用runtime遍历模型对象的所有属性,根据属性名从字典里取出相应的值,设置到模型的属性上)
-
KVO(利用runtime动态产生一个类)
-
objc_msgsend给对象发送消息
-
class_copymethodList遍历某个类的方法
-
class_copyIvarList遍历某个类的成员变量
-
class_...
-
class_getClassMethod 获取类方法
-
method_exchangeImplementations 方法交换
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
view.image = [UIImage imageNamed:@"pic_1"];
[self.view addSubview:view];
}
@end
#import "UIImage+ExTension.h"
#import <objc/runtime.h>
@implementation UIImage (ExTension)
//+ (void)load 只在加载时调用一次
+ (void)load{
NSLog(@"image load");
//get类方法
Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method m2 = class_getClassMethod([UIImage class], @selector(my_imageNamed:));
//方法交换
method_exchangeImplementations(m1, m2);
}
//自定义方法
+ (UIImage *)my_imageNamed:(NSString *)name{
//方法已经被置换,所以此时调用的my_imageNamed:实际上调用的是原方法imageNamed:
return [UIImage my_imageNamed:@"pic_2"];
}
@end
程序执行结果显示的就是pic_2,而不是pic_1。方法交换可以用于拦截在运行时拦截一些方法,在执行完自己想要的操作后再跳回该方法。
- +(void)load 是一个类方法 它在加载进内存时会调用一次
- +(void)initialize 会在第一次调用类的类方法或实例方法之前被调用一次。
runtime常识:
Ivar:成员变量,在runtime中,变量只有一个数据类型,就是Ivar
Method:成员方法
网友评论