Runtime是什么
Runtime是什么?其概念无非就是“因为 Objective-C 是一门动态语言,所以它需要一个运行时系统……Runtime 在实际开发中,其实就是一组C语言的函数,当然理解其运行机制对我们写出高质量的代码肯定有帮助,但是对于新手而言,概念听多了总是容易头晕。
所以新手只要知道 Runtime其实就是一组C语言的函数就可以了,但是想提高还是得啃掉这块骨头。
例如 OC的调用具体 C是怎么实现的:
[target doSomething] 会被转化成 objc_msgSend(target, @selector(doSomething));
还是前面的概念“Objective-C 是一门动态语言......”,相信大家刚接触OC的时候肯定肯定看过下面这个例子:
NSData * data = [NSData data]; NSString * str = data;
这段代码在编译的时候不会报错,只有在运行的时候才会报错,这就引出了我们今天的主题,利用 Runtime拿到实例变量,并赋值
实现具体功能
1. 在 OC中拿到类的实例变量核心代码
/* 获取对象的实例变量 */
- (NSArray *)getAllProperties{
u_int count;
Ivar *ivarList = class_copyIvarList([self class], &count);
NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++){
const char * ivarName = ivar_getName(ivarList[i]);
NSString * ivarStr = [NSString stringWithUTF8String: ivarName];
NSString * ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivarList[i])];
NSLog(@"%@",ivarType);
[propertiesArray addObject:ivarStr];
NSString * ivarKey = [ivarStr stringByReplacingOccurrencesOfString:@"_" withString:@""];
/* 属性赋值 */
[self PropertySetValue:ivarList[i] fotKey:ivarKey withType:ivarType];
}
free(ivarList);
self.propertiesArray = propertiesArray;
return propertiesArray;
}
这里也可以获取下面四个相关属性
相关属性:
// 描述类中的一个方法
typedef struct objc_method *Method;
// 实例变量
typedef struct objc_ivar *Ivar;
// 类别Category
typedef struct objc_category *Category;
// 类中声明的属性
typedef struct objc_property *objc_property_t;
2.属性赋值
其实只需要赋值的话,代码很少
拿到实例变量:
u_int count;
Ivar *ivarList = class_copyIvarList([self class], &count);
赋值:
object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value)
- obj 需要赋值的类
- ivar 需要赋值的实例变量
- value 给变量赋的值
OC中实现赋值核心代码
/* 属性赋值 */
- (void)PropertySetValue:(Ivar)ivar fotKey:(NSString*)key withType:(NSString*)type{
//获取 value 类型
DBModelValueType tpye = [DBModelType getModelType:type with:self.dataDic[key]];
/* 1. 嵌套赋值 属性赋值 */
if (tpye == DBModelValueType_selfClass) {
NSString * classStr = [type removeSymbol];
Class modelClass = NSClassFromString(classStr);
DBBaseModel * obj = [[modelClass alloc]initModel:self.dataDic[key]];
object_setIvar(self, ivar, obj);
}
/* 2. 数组赋值 属性赋值 */
if (tpye == DBModelValueType_NSArray) {
NSString * classStr = [type removeSymbol];
if ([classStr containsString:@"<"]) {
Class modelClass = NSClassFromString([classStr subStringFrom:@"<" to:@">"]);
NSMutableArray * modelArray = [NSMutableArray array];
NSArray * dataArrat = [NSArray arrayWithArray:self.dataDic[key]];
for (NSDictionary * dic in dataArrat) {
DBBaseModel * model = [[modelClass alloc]initModel:dic];
[modelArray addObject:model];
}
object_setIvar(self, ivar, modelArray);
}
}
/* 判断是否有多层级解析 */
if (![[self.HierarchyDic allKeys]containsObject:key] ) {
/* 3. 单层级 属性赋值 */
[DBModelConfig modelSetValue:self.dataDic[key] withClass:self withType:tpye withIvar:ivar];
}
else{
/* 4. 多层级 属性赋值 */
[DBModelConfig modelSetValue:self.dataDic withClass:self withType:tpye withIvar:ivar withHierarchyDic:self.HierarchyDic];
}
}
赋值的关键是需要判断变量的数据类型,这里需要特殊处理的是 NSDictionary , NSArray还有多层级的解析
测试数据结构如下:
NSDictionary * dic = @{@"sun":@"123",
@"dic":@{@"moon":@{@"hour":@"10:12"}},
@"price":@{@"rental":@{@"dayPrice":@"199"}},
@"list":@[@{@"key":@"1"},
@{@"key":@"2"},
@{@"key":@"3"}],
};
DBCarModel * model = [[DBCarModel alloc]initModel:dic];
NSLog(@"%@ %@ %@",model.sun,model.dayPrice,model.dic.hour);
打印的结果
2017-11-28 17:15:46.344759+0800 GMMC[81507:4313949] 123 199 10:12
- 多层级解析
模仿 JSONModel 在.m 里边添加获取层级关系函数
/* 获取层级关系字典 */
- (NSDictionary*)setValueWithHierarchy{
NSDictionary * dic = @{
@"dayPrice":@"price.rental.dayPrice"
};
return dic;
}
- 多层级 属性赋值
多层级需要拿到前面的层级关系HierarchyDic,来逐步解析数据
+ (void)modelSetValue:(id)value withClass:(id)class withType:(DBModelValueType)type withIvar:(Ivar)ivar withHierarchyDic:(NSDictionary*)HierarchyDic{
const char * ivarName = ivar_getName(ivar);
NSString * ivarStr = [NSString stringWithUTF8String: ivarName];
NSString * ivarKey = [ivarStr stringByReplacingOccurrencesOfString:@"_" withString:@""];
NSString * ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
NSArray * keyArray;
if ([[HierarchyDic allKeys]containsObject:ivarKey]) {
keyArray = [HierarchyDic[ivarKey] componentsSeparatedByString:@"."];
}
NSDictionary * newDic =[NSDictionary dictionaryWithDictionary:value];
NSString * newValue;
if (keyArray.count > 0) {
for (int i = 0; i < keyArray.count; i ++) {
newDic = newDic[keyArray[i]];
if (i == keyArray.count - 2) {
newValue = newDic[keyArray[i+1]];
break;
}
}
}
BOOL res_1 = [class isKindOfClass:[NSObject class]];
if (res_1) {
object_setIvar(class, ivar, newValue);
}
}
总结
这篇只是自己在学习时的一些记录,暂时就叫笔记吧。里边还有一些问题没有解决,看了也只会最基本的修改变量的值,具体用法还是需要自己去摸索学习。
大神请看这边
代码的健壮性稍后再说,这个例子里边还有一个问题就是 NSArray 类型的赋值会有问题最后还是源数据的字典。等找到问题解决方法在更新吧
网友评论