1. 程式人生 > >使用KVC進行字典轉模型

使用KVC進行字典轉模型

在專案中我們一般的都會碰到Json欄位請求回來進行模型封裝的情況,一般我們是建立一個Model然後Model裡面有Json請求回來的模型字典裡的各種欄位,類似 name,age…….之類的。封裝的時候拿到對應的模型字典,然後分別進行各個欄位的賦值,這個動作按照MVC的機制,一般都是放在模型裡面進行處理。類似於

-(void)toModelFromDictionary:(NSDictionary*)jsonDic{
self.name = jsonDic[@"name"];
self.age  = jsonDic[@"age"];
}

這樣的話有幾個弊端:
1、後臺請求回來的字典資料有可能是各種型別的,比如NSNumber,Nsstring,等,如果後臺的某個欄位為空,那麼就會導致程式崩潰。
2、欄位比較多的話,手寫字典轉模型就很累人了。。

解決辦法有兩個:
1. 使用一個第三方控制元件,李明傑老師的MJExtension,這個控制元件可以做到字典轉模型,模型裡面還可以套結模型,也可以套接模型陣列,功能比較完善和強大。
功能點:
JSON –> Model、Core Data Model
JSONString –> Model、Core Data Model
Model、Core Data Model –> JSON
JSON Array –> Model Array、Core Data Model Array
JSONString –> Model Array、Core Data Model Array
Model Array、Core Data Model Array –> JSON Array
Coding all properties of model in one line code.

  1. 如果你不想用第三方控制元件,感覺自由度太低,比較受限制,那麼可以嘗試這種方法,使用 KVC 機制的 如下方法
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;

這個函式能夠做到的事情就是把模型裡對應的屬性按照keyedValues裡的字典鍵值對進行復制,完成模型的初步轉化,這裡注意,如果你不做任何處理,那麼模型裡的屬性型別必須和字典裡的值對應,比如字典裡的時NSnumber 那麼屬性型別也必須是NSnumber.

有沒有辦法讓所有的型別統一一下,處理起來沒這麼麻煩要做到型別的一一對應?可以在模型裡實現如下方法,系統自動呼叫

// 將所有的資料轉換為字串
-(void)setValue:(id)value forKey:(NSString *)key{

    if([value isKindOfClass:[NSNull class]]){
        value=nil;
    }else if([value isKindOfClass:[NSArray class]]){
    }else{
        value = [NSString stringWithFormat:@"%@",value];
    }
    [super setValue:value forKey:key];
}

// 對特殊字元 id 進行處理
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"Undefined Key: %@", key);
}

可以封裝一個BaseModel 實現上面兩個方法,建立如下轉模型方法

// 字典轉模型
-(id)initWithDic:(NSDictionary *)modelDic{

    self = [super init];
    if(self){
        [self setValuesForKeysWithDictionary:modelDic];
    }
    return self;

}

使用的時候大概是這樣:

EmployeModel *aEmploye = [[EmployeModel alloc]initWithDic:employeeDic];

如果我們還想要進行模型裡的模型巢狀,或者模型裡的模型陣列或者其他處理怎麼辦?
在EmployeModel裡面複寫BaseModel裡面的 setValueForKey比如我的EmployeModel裡面還有個times 的字典陣列,數組裡面又是模型,單獨處理。除此之外,我們還可以進行其他的一些資料微調處理。

- (void)setValue:(id)value forKey:(NSString *)key{

//    去掉從通訊錄匯出來時出現的 -
    if ([key isEqualToString:@"mobile"]) {
        NSArray *arr = [(NSString *)value componentsSeparatedByString:@"-"];
        value = [arr componentsJoinedByString:@""];
    }else if([key isEqualToString:@"times"]){

        NSMutableArray *retArr = [NSMutableArray array];

        for (int i=0; i<((NSArray *)value).count; i++) {

            NSDictionary * aDayTimeDic = ((NSArray *)value)[i];
            TimeModel *aDayTime = [[TimeModel alloc]initWithDic:aDayTimeDic];
            [retArr addObject:aDayTime];

        }
        value = retArr;
    }
    [super setValue:value forKey:key];
}