最近公司后台变动。导致网络框架近乎废弃。需求紧急,情急之下,我只能先完成工作再慢慢优化。
开始写的字典转模型代码都能恶心到自己。
eg.
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
//方法one
// self.price = dict[@"price"];
// self.buyNum = dict[@"buyNum"];
// self.image = dict[@"image"];
// self.name = dict[@"name"];
//方法two
// for (id key in dict) {
// [self setValue:dict[key] forKey:key];
// }
//方法three
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"没有找到key:%@",key);
}
+ (instancetype)productInfoWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
虽然说用了kvc,但是这样的代码确实恶心。于是回忆了一下。用运行时改造了下代码。至少能安慰了自己。
+ (instancetype)productInfoWithDict:(NSDictionary *)dict{
// return [[self alloc] initWithDict:dict];
id object = [[self alloc] init];
unsigned int count = 0;
//获取成员属性列表
Ivar *ivarList = class_copyIvarList(self, &count);
for (int i=0; i<count; i++) {
//获取成员属性
Ivar ivar = ivarList[i];
//获取成员名
NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
//获取成员属性
//NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
//获取key 从1开始是为了 干掉_
NSString *key = [propertyName substringFromIndex:1];
//这里可以写方法,来区分本地跟后台不一样的字段名即可
//例如:model取名字为productPrice。后台字段返回为product_price
//if([key isEqualToString:@"productPrice"]){
// key = @"product_price";
//}
id value = dict[key];
if (value) {
[object setValue:value forKey:key];
}
}
return object;
}
以下是封装的比较全的字典转模型的方法。
- (void)transformObjFromDic:(NSDictionary *) objDic
{
if (objDic.count == 0) {
return;
}
Class theClass = [self class];
while (theClass != [VCObjTransformSuperModel class]) {
unsigned int attCount;
/* retain, creat, copy 需要release */
objc_property_t *properties = class_copyPropertyList(theClass, &attCount);
for (int i = 0; i < attCount; i++) {
objc_property_t property = properties[i];
const char *attName = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:attName];
NSString *rePropertyName = [self keyNameReflactToAttributeName:propertyName];
id value = [objDic objectForKey:rePropertyName];
// const char *attType = property_getAttributes(property);
if (value == nil || [value isKindOfClass:[NSNull class]]) {
continue;
}else if ([value isKindOfClass:[NSDictionary class]]){
Class attClass = [self classReflactToAttributeName:propertyName];
if ([attClass conformsToProtocol:@protocol(VCObjTransformProtocol)]) {
id<VCObjTransformProtocol> attObj = [[[attClass class] alloc] init];
[attObj transformObjFromDic:value];
[self setValue:attObj forKey:propertyName];
}else{
if (attClass) {
[self setValue:value forKey:propertyName];
}
}
}else if ([value isKindOfClass:[NSArray class]]){//数组
NSArray *valueArray = (NSArray *)value;
if (valueArray.count == 0) {//数组为空返回
continue;
}
NSMutableArray *attObjArray = [NSMutableArray array];
Class attClass = [self classReflactToAttributeName:propertyName];
if ([attClass conformsToProtocol:@protocol(VCObjTransformProtocol)]) {//是否是遵守协议的对象
for (id valueObj in value) {
id<VCObjTransformProtocol> attObj = [[[attClass class] alloc] init];
[attObj transformObjFromDic:valueObj];
[attObjArray addObject:attObj];
}
}else{
for (id valueObj in value) {
if ([valueObj isKindOfClass:[NSDictionary class]]) {
[attObjArray addObject:valueObj];
}else if ([valueObj isKindOfClass:[NSNumber class]]){
[attObjArray addObject:valueObj];
}else{
[attObjArray addObject:valueObj];
}
}
}
[self setValue:attObjArray forKey:propertyName];
}else if ([value isKindOfClass:[NSNumber class]]){
const char *att = property_getAttributes(property);
NSString *attType = [NSString stringWithUTF8String:att];
NSRange range = [attType rangeOfString:@"NSString"];
if(range.location != NSNotFound){
NSNumber *newValueNum = (NSNumber *) value;
[self setValue:[newValueNum stringValue] forKey:propertyName];
}else{
[self setValue:value forKey:propertyName];
}
}else{
//TODO:hai 最好还能将string转为自定义的基本类型
[self setValue:value forKey:propertyName];
}
}
//创建时候计数器+1 这里需要释放。
free(properties);
//获取theClass的父类
theClass = class_getSuperclass(theClass);
}
}
有什么不理解随时沟通。
网友评论