根據(jù)前面的學習iOS開發(fā)之使用Runtime給Model類賦值和OC和Swift中的Runtime塞弊,總結(jié)一下將字典轉(zhuǎn)換成模型(字典key不和屬性一一對應漱逸,并且模型中有模型)
字典轉(zhuǎn)模型
1、 創(chuàng)建分類
ls_assginToPropertyWithDictionary
在分類中實現(xiàn)游沿,前面iOS開發(fā)之使用Runtime給Model類賦值功能饰抒,前面有詳細的實現(xiàn)步驟,在這里不做重復诀黍,直接上代碼
//
// NSObject+Model.m
// LSRuntimeOCDemo
//
// Created by a110 on 16/4/19.
// Copyright ? 2016年 a110. All rights reserved.
//
#import "NSObject+Model.h"
@implementation NSObject (LSModel)
#pragma mark -- 通過字符串來創(chuàng)建該字符串的Setter方法袋坑,并返回
- (SEL) ls_creatSetterWithPropertyName: (NSString *) propertyName{
//1.首字母大寫
propertyName = propertyName.capitalizedString;
//2.拼接上set關(guān)鍵字
propertyName = [NSString stringWithFormat:@"set%@:", propertyName];
//3.返回set方法
return NSSelectorFromString(propertyName);
}
/************************************************************************
*把字典賦值給當前實體類的屬性
*參數(shù):字典
*適用情況:當網(wǎng)絡請求的數(shù)據(jù)的key與實體類的屬性相同時可以通過此方法吧字典的Value
* 賦值給實體類的屬性
************************************************************************/
-(void) ls_assginToPropertyWithDictionary: (NSDictionary *) data{
if (data == nil) {
return;
}
///1.獲取字典的key
NSArray *dicKey = [data allKeys];
///2.循環(huán)遍歷字典key, 并且動態(tài)生成實體類的setter方法,把字典的Value通過setter方法
///賦值給實體類的屬性
for (int i = 0; i < dicKey.count; i ++) {
///2.1 通過getSetterSelWithAttibuteName 方法來獲取實體類的set方法
SEL setSel = [self ls_creatSetterWithPropertyName:dicKey[i]];
if ([self respondsToSelector:setSel]) {
///2.2 獲取字典中key對應的value
// NSString *value = [NSString stringWithFormat:@"%@", data[dicKey[i]]];
// 根據(jù)成員屬性名去字典中查找對應的value
id value = data[dicKey[i]];
NSString *key=dicKey[i];
// 二級轉(zhuǎn)換:如果字典中還有字典眯勾,也需要把對應的字典轉(zhuǎn)換成模型
// 判斷下value是否是字典
if ([value isKindOfClass:[NSDictionary class]]) {
// 根據(jù)字符串類名生成類對象
Class modelClass = NSClassFromString(key);
if (modelClass) { // 有對應的模型才需要轉(zhuǎn)
// 把字典轉(zhuǎn)模型
value = [modelClass ls_modelWithDictionary:value];
}
}
// 三級轉(zhuǎn)換:NSArray中也是字典枣宫,把數(shù)組中的字典轉(zhuǎn)換成模型.
// 判斷值是否是數(shù)組
if ([value isKindOfClass:[NSArray class]]) {
// 判斷對應類有沒有實現(xiàn)字典數(shù)組轉(zhuǎn)模型數(shù)組的協(xié)議
if ([self respondsToSelector:@selector(ls_arrayContainModelClass)]) {
// 轉(zhuǎn)換成id類型,就能調(diào)用任何對象的方法
// id idSelf = self;
// 獲取數(shù)組中字典對應的模型
NSString *type = [self ls_arrayContainModelClass][key];
// 生成模型
Class classModel = NSClassFromString(type);
NSMutableArray *arrM = [NSMutableArray array];
// 遍歷字典數(shù)組吃环,生成模型數(shù)組
for (NSDictionary *dict in value) {
// 字典轉(zhuǎn)模型
id model = [classModel ls_modelWithDictionary:dict];
[arrM addObject:model];
}
// 把模型數(shù)組賦值給value
value = arrM;
}
}
if (value) { // 有值也颤,才需要給模型的屬性賦值
///2.3 把值通過setter方法賦值給實體類的屬性
[self performSelectorOnMainThread:setSel
withObject:value
waitUntilDone:[NSThread isMainThread]];
}
}
}
}
///通過運行時獲取當前對象的所有屬性的名稱,以數(shù)組的形式返回
const char *propertiesKey = "propertiesKey";
- (NSArray *) ls_allPropertyNames{
//參數(shù)一 關(guān)聯(lián)到對象
//參數(shù)二 關(guān)聯(lián)的屬性key
//在oc 中 類的本質(zhì)就是一個對象 將屬性列表緩存
NSArray *plist = objc_getAssociatedObject(self, propertiesKey);
if(plist != nil)
{
return plist;
}
///存儲所有的屬性名稱
NSMutableArray *allNames = [[NSMutableArray alloc] init];
///存儲屬性的個數(shù)
unsigned int propertyCount = 0;
///通過運行時獲取當前類的屬性
objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount);
//把屬性放到數(shù)組中
for (int i = 0; i < propertyCount; i ++) {
///取出第一個屬性
objc_property_t property = propertys[i];
const char * propertyName = property_getName(property);
[allNames addObject:[NSString stringWithUTF8String:propertyName]];
}
///釋放
free(propertys);
//5 設置關(guān)聯(lián)對象
//參數(shù)1>關(guān)聯(lián)的對象
//參數(shù)2>關(guān)聯(lián)對象的key
//參數(shù)3>屬性數(shù)值
//屬性的持有方式 retain copy assign
objc_setAssociatedObject(self, propertiesKey, allNames, OBJC_ASSOCIATION_COPY_NONATOMIC);
return allNames;
}
#pragma mark -- 通過字符串來創(chuàng)建該字符串的Setter方法模叙,并返回
- (SEL) ls_creatGetterWithPropertyName: (NSString *) propertyName{
//1.返回get方法: oc中的get方法就是屬性的本身
return NSSelectorFromString(propertyName);
}
#pragma 返回屬性和字典key的映射關(guān)系
-(NSDictionary *) ls_propertyMapDic{
return nil;
}
///返回數(shù)組轉(zhuǎn)換模型的映射關(guān)系
-(NSDictionary *)ls_arrayContainModelClass{
return nil;
}
#pragma 根據(jù)映射關(guān)系來給Model的屬性賦值
-(void) ls_assginToPropertyWithNoMapDictionary: (NSDictionary *) data{
///獲取字典和Model屬性的映射關(guān)系
NSDictionary *propertyMapDic = [self ls_propertyMapDic];
///轉(zhuǎn)化成key和property一樣的字典歇拆,然后調(diào)用assginToPropertyWithDictionary方法
NSArray *dicKey = [data allKeys];
NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:dicKey.count];
for (int i = 0; i < dicKey.count; i ++) {
NSString *key = dicKey[i];
[tempDic setObject:data[key] forKey:propertyMapDic[key]];
}
[self ls_assginToPropertyWithDictionary:tempDic];
}
+ (instancetype)initWithDictionary: (NSDictionary *) data{
{
id objc = [[self alloc] init];
if (self) {
if ([objc ls_propertyMapDic] == nil) {
[objc ls_assginToPropertyWithDictionary:data];
} else {
[objc ls_assginToPropertyWithNoMapDictionary:data];
}
}
return objc;
}
}
+ (instancetype)ls_modelWithDictionary: (NSDictionary *) data{
return [self initWithDictionary:data];
}
#pragma mark -- 獲取所有屬性的值
- (void) ls_displayCurrentModleProperty{
//獲取實體類的屬性名
NSArray *array = [self ls_allPropertyNames];
//拼接參數(shù)
NSMutableString *resultString = [[NSMutableString alloc] init];
for (int i = 0; i < array.count; i ++) {
//獲取get方法
SEL getSel = [self ls_creatGetterWithPropertyName:array[i]];
if ([self respondsToSelector:getSel]) {
//獲得類和方法的簽名
NSMethodSignature *signature = [self methodSignatureForSelector:getSel];
//從簽名獲得調(diào)用對象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//設置target
[invocation setTarget:self];
//設置selector
[invocation setSelector:getSel];
//接收返回的值
NSObject *__unsafe_unretained returnValue = nil;
//調(diào)用
[invocation invoke];
//接收返回值
[invocation getReturnValue:&returnValue];
[resultString appendFormat:@"%@\n", returnValue];
}
}
NSLog(@"%@", resultString);
}
@end
值得注意的是:
#pragma 返回屬性和字典key的映射關(guān)系
-(NSDictionary *) ls_propertyMapDic{
return nil;
}
///返回數(shù)組轉(zhuǎn)換模型的映射關(guān)系
-(NSDictionary *)ls_arrayContainModelClass{
return nil;
}
這兩個方法,是必要時需要在自定義類中實現(xiàn)
上面的ls_assginToPropertyWithDictionary方法中,將之前的兩篇文章結(jié)合故觅。
2厂庇、創(chuàng)建自己的model
//
// Status.h
// LSRuntimeOCDemo
//
// Created by a110 on 16/4/19.
// Copyright ? 2016年 a110. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "NSObject+Model.h"
#import "sta.h"
@interface Status : NSObject
@property(nonatomic,copy)NSArray *aa;
@property(nonatomic,copy)sta *bb;
@property(nonatomic,copy)NSString *cc;
@end
//
// Status.h
// LSRuntimeOCDemo
//
// Created by a110 on 16/4/19.
// Copyright ? 2016年 a110. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "NSObject+Model.h"
#import "sta.h"
@interface Status : NSObject
@property(nonatomic,copy)NSArray *aa;
@property(nonatomic,copy)sta *bb;
@property(nonatomic,copy)NSString *cc;
@end
可以看出,在Status中既有數(shù)組又有sta模型输吏。
需要在Status中實現(xiàn)
-(NSDictionary *)ls_arrayContainModelClass{
NSDictionary *dic=@{@"aa":@"sta"};
return dic;
}
-(NSDictionary *)ls_propertyMapDic{
return @{@"cc1":@"cc",@"aa":@"aa",@"bb":@"bb"};
}
//這里因為在ls_assginToPropertyWithDictionary方法中直接將value進行setter給key會報錯权旷,所以重寫了setter方法,總覺得哪里不對贯溅,還需要學習
-(void)setBb:(sta *)bb{
_bb=bb;
}
測試一下:
NSDictionary* dic=@{@"cc1":@"ccccccccc",@"bb":@{@"status":@"status=1",@"name":@"name=2"},@"aa":@[@{@"status":@"status=1",@"name":@"name=2"}]};
Status *status=[Status ls_modelWithDictionary:dic];
NSLog(@"%@",status.aa);
打印結(jié)果
2016-04-22 17:29:17.371 LSRuntimeOCDemo[2801:280574] (
"<sta: 0x7f8791408150>"
)
模型轉(zhuǎn)字典?
#pragma mark -- model轉(zhuǎn)為字典
- (NSDictionary*) ls_dictionaryWithModel
測試
NSDictionary* dic=@{@"cc1":@"ccccccccc",@"bb":@{@"status":@"status=1",@"name":@"name=2"},@"aa":@[@{@"status":@"status=1",@"name":@"name=2"}]};
Status *status=[Status ls_modelWithDictionary:dic];
NSLog(@"%@",status.aa);
NSDictionary *dictionary=[status ls_dictionaryWithModel];
NSLog(@"%@",dictionary);
打印結(jié)果
2016-04-22 17:50:14.186 LSRuntimeOCDemo[2850:292737] {
aa = (
"<sta: 0x7f8a70d08070>"
);
bb = {
name = "name=2";
status = "status=1";
};
cc = ccccccccc;
}