- runTime 是一套比较底层的纯C语言API,属于1个C语言库,包含了很多底层的C语言API.我们平时编写的OC代码,在程序运行时,最终都是转成了Runtime 的C 语言代码.
runTime 是 OC 消息机制的平台,例如OC 函数的调用,在编译的时候并不能真正决定调用哪个函数,只有在程序真正运行的时候才会根据函数名找到对应的方法来调用
运行时机制,我们在开发中使用的比较多的有三个方法.第一个就是动态获取属性.第二个就是动态为分类添加属性.第三个就是俗称黑魔法的替换方法.也就是在编译的过程中将系统或者分类的方法替换成我们想要的方法.
1)程序运行时,动态创建一个类(比如KVO的底层实现)
2)程序运行时,动态地为某个类添加属性/方法,修改属性值/方法
3)遍历一个类的所有成员变量/方法, 例如,我们对一个类进行归档解档的时候,如果属性特别多,这时候我们需要很多代码,但是使用runtime,就可以动态设置
2.应用场景
1)NSCoding (归档解档,利用runtime 遍历对象的所有属性)
2)字典->模型,利用runtime遍历模型的所有属性,根据属性从名字中取出对应的值,设置到模型的属性上
3)KVO ,利用runtime 动态产生一个类
4)利用关联对象 给分类添加属性.
5)用于封装框架,主要用于给分类解耦或者动态设置属性
下面是几个应用的实例代码:
1) json转模型
原理,利用 runtime 提供的函数,遍历 模型自身所有属性,如果在json 中有对应的值,则将其赋值
下面是一个demo,演示了怎么利用 runtime,进行字典转模型,以及归档解档操作:
点我下载
- (instancetype)initWithDict:(NSDictionary *)dict {
if (self = [self init]) {
//(1)获取类的属性及属性对应的类型
NSMutableArray * keys = [NSMutableArray array];
NSMutableArray * attributes = [NSMutableArray array];
unsigned int outCount;
objc_property_t * properties = class_copyPropertyList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
objc_property_t property = properties[i];
//通过property_getName函数获得属性的名字
NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[keys addObject:propertyName];
//通过property_getAttributes函数可以获得属性的名字和@encode编码
NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
[attributes addObject:propertyAttribute];
}
//立即释放properties指向的内存
free(properties);
//(2)根据类型给属性赋值
for (NSString * key in keys) {
if ([dict valueForKey:key] == nil) continue;
[self setValue:[dict valueForKey:key] forKey:key];
}
}
return self;
}
2.对自定义类进行归档解档
原理:利用 runtime 提供的函数对模型自身所有属性进行遍历,并进行encode 和 decode操作
#pragma mark - runtime 归档解档
// 解档
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
unsigned int outCount;
Ivar * ivars = class_copyIvarList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
Ivar ivar = ivars[i];
NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
[self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
}
}
return self;
}
// 归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int outCount;
Ivar * ivars = class_copyIvarList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
Ivar ivar = ivars[i];
NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
[aCoder encodeObject:[self valueForKey:key] forKey:key];
}
}