国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

最簡單的 json或字典 轉(zhuǎn) model

2019-11-09 18:17:56
字體:
供稿:網(wǎng)友

前言

我們在iOS開發(fā)中,一般會使用MVC或者MVVM等模式。當(dāng)我們從接口中拿到數(shù)據(jù)時,我們需要把數(shù)據(jù)轉(zhuǎn)成模型使用。下面我就帶大家一起用runtime一步一步的來完成這個轉(zhuǎn)換框架.(比較簡單的model不用runtime也可以的) .

1、先寫一個簡單的字典到模型的轉(zhuǎn)換

模型TestModel
@interface TestModel : NSObject@PRoperty (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSString *phone;@property (nonatomic, copy) NSString *address;@property (nonatomic, assign) NSInteger age;@end控制器ViewController中
@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    self.title = @"字典轉(zhuǎn)模型";    NSDictionary *dicTest = @{@"name":@"張三",                              @"phone":@"110",                              @"age":@"10"};    TestModel *model = [TestModel yj_initWithDictionary:dicTest];    NSLog(@"model-----name:%@, phone:%@, address:%@, age:%@", model.name, model.phone, model.address, @(model.age));}@end字典轉(zhuǎn)模型的分類中
@implementation NSObject (YJModelDicTransform)//字典轉(zhuǎn)模型+ (instancetype)yj_initWithDictionary:(NSDictionary *)dic{    id myObj = [[self alloc] init];    unsigned int outCount;    //獲取類中的所有成員屬性    objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount);    for (NSInteger i = 0; i < outCount; i ++) {        objc_property_t property = arrPropertys[i];        //獲取屬性名字符串        //model中的屬性名        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];        id propertyValue = dic[propertyName];        if (propertyValue != nil) {            [myObj setValue:propertyValue forKey:propertyName];        }    }    free(arrPropertys);    return myObj;}控制臺打印

2016-12-19 15:55:18.231 YJModelDicTransform[1627:125724] model-----name:張三, phone:110, address:(null), age:10

這個地方我覺得這里是不需要用runtime啊, 比如這樣寫,同樣可以完成需求,當(dāng)然需要保證dic中key和 屬性一一對應(yīng).       NSArray *keyArray = [dict allKeys];                    for (NSString *key in keyArray) {              [self setValue:dict[key] forKey:key] ;          }這個方法也要有,防止服務(wù)器出錯時的崩潰- (void)setValue:(id)value forUndefinedKey:(NSString *)key  {        }到這步,我的需求基本就完了,但是還是向下看下,學(xué)習(xí)學(xué)習(xí) .

2、模型中嵌套有模型

第一步完成后我們已經(jīng)可以自動完成字典和模型的轉(zhuǎn)換了,但是還不完善,比如我們的字典的value中如果有字典或者數(shù)組類型的話,程序就識別不了,所以我們現(xiàn)在就來處理這種情況

先通過runtime來獲取模型中屬性的類型,然后根據(jù)不同類型來處理

@interface TestModel : NSObject@property (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSString *phone;@property (nonatomic, copy) NSString *address;@property (nonatomic, assign) NSInteger age;//模型中嵌套UserModel模型@property (nonatomic, strong) UserModel *user;@end@interface UserModel : NSObject@property (nonatomic, copy) NSString *userName;@property (nonatomic, copy) NSString *userId;@end
NSString *const YJClassType_object  =   @"對象類型";NSString *const YJClassType_basic   =   @"基礎(chǔ)數(shù)據(jù)類型";NSString *const YJClassType_other   =   @"其它";
@implementation NSObject (YJModelDicTransform)+ (instancetype)yj_initWithDictionary:(NSDictionary *)dic{    id myObj = [[self alloc] init];    unsigned int outCount;    //獲取類中的所有成員屬性    objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount);    for (NSInteger i = 0; i < outCount; i ++) {        objc_property_t property = arrPropertys[i];        //獲取屬性名字符串        //model中的屬性名        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];        id propertyValue = dic[propertyName];        if (propertyValue == nil) {            continue;        }        //獲取屬性是什么類型的        NSDictionary *dicPropertyType = [self propertyTypeFromProperty:property];        NSString *propertyClassType = [dicPropertyType objectForKey:@"classType"];        NSString *propertyType = [dicPropertyType objectForKey:@"type"];        if ([propertyType isEqualToString:YJClassType_object]) {            if ([propertyClassType isEqualToString:@"NSArray"] || [propertyClassType isEqualToString:@"NSMutableArray"]) {                //數(shù)組類型,現(xiàn)在還用不了,因為還沒有方法知道數(shù)組中保存的是什么類型,后面會處理            }            else if ([propertyClassType isEqualToString:@"NSDictionary"] || [propertyClassType isEqualToString:@"NSMutableDictionary"]) {                //字典類型   不考慮,一般不會用字典,用自定義model            }            else if ([propertyClassType isEqualToString:@"NSString"]) {                //字符串類型                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }            else {                //自定義類型,循環(huán)調(diào)用,一直到不是自定義類型                propertyValue = [NSClassFromString(propertyClassType) yj_initWithDictionary:propertyValue];                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }        }        else if ([propertyType isEqualToString:YJClassType_basic]) {            //基本數(shù)據(jù)類型            if ([propertyClassType isEqualToString:@"c"]) {                //bool類型                NSString *lowerValue = [propertyValue lowercaseString];                if ([lowerValue isEqualToString:@"yes"] || [lowerValue isEqualToString:@"true"]) {                    propertyValue = @(YES);                } else if ([lowerValue isEqualToString:@"no"] || [lowerValue isEqualToString:@"false"]) {                    propertyValue = @(NO);                }            }            else {                propertyValue = [[[NSNumberFormatter alloc] init] numberFromString:propertyValue];            }            if (propertyValue != nil) {                [myObj setValue:propertyValue forKey:propertyName];            }        }        else {            //其他類型        }    }    free(arrPropertys);    return myObj;}//獲取屬性的類型- (NSDictionary *)propertyTypeFromProperty:(objc_property_t)property{    //獲取屬性的類型, 類似 T@"NSString",C,N,V_name    T@"UserModel",&,N,V_user    NSString *propertyAttrs = @(property_getAttributes(property));    NSMutableDictionary *dicPropertyType = [NSMutableDictionary dictionary];    //截取類型    NSRange commaRange = [propertyAttrs rangeOfString:@","];    NSString *propertyType = [propertyAttrs substringWithRange:NSMakeRange(1, commaRange.location - 1)];    NSLog(@"屬性類型:%@, %@", propertyAttrs, propertyType);    if ([propertyType hasprefix:@"@"] && propertyType.length > 2) {        //對象類型        NSString *propertyClassType = [propertyType substringWithRange:NSMakeRange(2, propertyType.length - 3)];        [dicPropertyType setObject:propertyClassType forKey:@"classType"];        [dicPropertyType setObject:YJClassType_object forKey:@"type"];    }    else if ([propertyType isEqualToString:@"q"]) {        //NSInteger類型        [dicPropertyType setObject:@"NSInteger" forKey:@"classType"];        [dicPropertyType setObject:YJClassType_basic forKey:@"type"];    }    else if ([propertyType isEqualToString:@"d"]) {        //CGFloat類型        [dicPropertyType setObject:@"CGFloat" forKey:@"classType"];        [dicPropertyType setObject:YJClassType_basic forKey:@"type"];    }    else if ([propertyType isEqualToString:@"c"]) {        //BOOL類型        [dicPropertyType setObject:@"BOOL" forKey:@"classType"];        [dicPropertyType setObject:YJClassType_basic forKey:@"type"];    }    else {        [dicPropertyType setObject:YJClassType_other forKey:@"type"];    }    return dicPropertyType;}控制器中
- (void)viewDidLoad {    [super viewDidLoad];    self.title = @"字典轉(zhuǎn)模型";    NSDictionary *dicTest = @{@"name":@"張三",                              @"phone":@"110",                              @"age":@"10",                              @"user":@{@"userId":@"2"}};    TestModel *model = [TestModel yj_initWithDictionary:dicTest];    NSLog(@"model-----name:%@, phone:%@, address:%@, age:%@, userId:%@, userName:%@", model.name, model.phone, model.address, @(model.age), model.user.userId, model.user.userName);}控制臺打印

2016-12-19 16:39:52.079 YJModelDicTransform[1851:143085] 屬性類型:T@"NSString",C,N,V_name, @"NSString"

2016-12-19 16:39:52.080 YJModelDicTransform[1851:143085] 屬性類型:T@"NSString",C,N,V_phone, @"NSString"

2016-12-19 16:39:52.080 YJModelDicTransform[1851:143085] 屬性類型:Tq,N,V_age, q

2016-12-19 16:39:52.081 YJModelDicTransform[1851:143085] 屬性類型:T@"UserModel",&,N,V_user, @"UserModel"

2016-12-19 16:39:52.081 YJModelDicTransform[1851:143085] 屬性類型:T@"NSString",C,N,V_userId, @"NSString"

2016-12-19 16:39:52.081 YJModelDicTransform[1851:143085] model-----name:張三, phone:110, address:(null), age:10, userId:2, userName:(null)

在類中的聲明為 

T@“NSNumber” 標(biāo)記了屬于什么類型N            線程安全 相當(dāng)與Objective-C中的nonmaticR            不可變,R相當(dāng)與Objective-C中的readonly,C相當(dāng)于copy        V_name        去掉V_,name就是變量名

通過對type進行處理就可以獲得屬性的類型。從而進行下一步處理。

注意點:class_copyPropertyList返回的僅僅是對象類的屬性,class_copyIvarList返回類的所有屬性和變量,在swift中如let a: Int? 是無法通過class_copyPropertyList返回的。

看完了,開個簡化版吧,  我是讓model都繼承rootModel, 他采用了給NSObject加類別, 都可以,   加類別 好處是 現(xiàn)有的工程幾乎不用動,壞處是,以后再擴展不太方便  ,   繼承rootModel好處是 擴展容易 , 比較適合一個新的工程 .
+ (id)objectWithDictionary:(NSDictionary * )dic  {            id myObj = [[self alloc] init];        unsigned int outCount;        //獲取類中的所有成員屬性    objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount);        for (NSInteger i = 0; i < outCount; i ++) {        objc_property_t property = arrPropertys[i];                //獲取屬性名字符串        //model中的屬性名        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];        id propertyValue = dic[propertyName];                if ([propertyValue isKindOfClass:[NSDictionary class] ]) {            NSString * valueType =[self getPropertyType: property ];            Class valueClass = NSClassFromString(valueType) ;            // 遞歸調(diào)用,多少層的model都可以,            id value = [valueClass objectWithDictionary:propertyValue];            [myObj setValue:value forKey:propertyName];            continue ;        }                if (propertyValue != nil) {            [myObj setValue:propertyValue forKey:propertyName];        }    }        free(arrPropertys);    //         -------------------方法二 : 不用runtime試試, 經(jīng)過拼命掙扎, 結(jié)果表明,只能對簡單模型有效,對模型嵌套無效,主要失敗原因,不能動態(tài)的獲得嵌套模型的類名,獲得類名或許只能通過runtime了//        for (NSString * key in dic.allKeys) {//    //            [myObj setValue:dic[key] forKey:key ];//    //        }//        return myObj;}+ (NSString *) getPropertyType:(objc_property_t)property {        //獲取屬性的類型, 類似 T@"NSString",C,N,V_name    T@"UserModel",&,N,V_user    NSString *propertyAttrs = @(property_getAttributes(property));        //截取類型    NSRange commaRange = [propertyAttrs rangeOfString:@","];    NSString *propertyType = [propertyAttrs substringWithRange:NSMakeRange(3, commaRange.location - 4)];    NSLog(@"屬性類型:%@, 截取后%@", propertyAttrs, propertyType);        return propertyType ;    }

3、處理模型中有數(shù)組屬性的情況

第二步之后程序可以處理模型中包含模型的情況, 但是還不能處理模型中有數(shù)組的情況,因為數(shù)組中存儲的類型需要人為的告訴程序,下面我們添加一個協(xié)議來來處理這種情況

先創(chuàng)建一個協(xié)議, 然后讓分類遵循它

@protocol YJModelDicTransform <NSObject>@optional/** *  數(shù)組中存儲的類型 * *  @return key --- 屬性名,  value --- 數(shù)組中存儲的類型 */+ (NSDictionary *)yj_objectClassInArray;@end@interface NSObject (YJModelDicTransform)<YJModelDicTransform>+ (instancetype)yj_initWithDictionary:(NSDictionary *)dic;@end在model中實現(xiàn)這個方法
@implementation TestModel+ (NSDictionary *)yj_objectClassInArray{    return @{@"arrUsers":@"UserModel"};}+ (NSDictionary *)yj_propertykeyReplacedWithValue{    return @{@"_id":@"id"};}@end
//字典轉(zhuǎn)模型+ (instancetype)yj_initWithDictionary:(NSDictionary *)dic{    id myObj = [[self alloc] init];    unsigned int outCount;    //獲取類中的所有成員屬性    objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount);    for (NSInteger i = 0; i < outCount; i ++) {        objc_property_t property = arrPropertys[i];        //獲取屬性名字符串        //model中的屬性名        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];        id propertyValue = dic[propertyName];        if (propertyValue == nil) {            continue;        }        //獲取屬性是什么類型的        NSDictionary *dicPropertyType = [self propertyTypeFromProperty:property];        NSString *propertyClassType = [dicPropertyType objectForKey:@"classType"];        NSString *propertyType = [dicPropertyType objectForKey:@"type"];        if ([propertyType isEqualToString:YJClassType_object]) {            if ([propertyClassType isEqualToString:@"NSArray"] || [propertyClassType isEqualToString:@"NSMutableArray"]) {                //數(shù)組類型                if ([self respondsToSelector:@selector(yj_objectClassInArray)]) {                    id propertyValueType = [[self yj_objectClassInArray] objectForKey:propertyName];                    if ([propertyValueType isKindOfClass:[NSString class]]) {                        propertyValue = [NSClassFromString(propertyValueType) yj_initWithArray:propertyValue];                    }                    else {                        propertyValue = [propertyValueType yj_initWithArray:propertyValue];                    }                    if (propertyValue != nil) {                        [myObj setValue:propertyValue forKey:propertyName];                    }                }            }            else if ([propertyClassType isEqualToString:@"NSDictionary"] || [propertyClassType isEqualToString:@"NSMutableDictionary"]) {                //字典類型   不考慮,一般不會用字典,用自定義model            }            else if ([propertyClassType isEqualToString:@"NSString"]) {                //字符串類型                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }            else {                //自定義類型,循環(huán)調(diào)用,一直到不是自定義類型                propertyValue = [NSClassFromString(propertyClassType) yj_initWithDictionary:propertyValue];                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }        }        else if ([propertyType isEqualToString:YJClassType_basic]) {            //基本數(shù)據(jù)類型            if ([propertyClassType isEqualToString:@"c"]) {                //bool類型                NSString *lowerValue = [propertyValue lowercaseString];                if ([lowerValue isEqualToString:@"yes"] || [lowerValue isEqualToString:@"true"]) {                    propertyValue = @(YES);                } else if ([lowerValue isEqualToString:@"no"] || [lowerValue isEqualToString:@"false"]) {                    propertyValue = @(NO);                }            }            else {                propertyValue = [[[NSNumberFormatter alloc] init] numberFromString:propertyValue];            }            if (propertyValue != nil) {                [myObj setValue:propertyValue forKey:propertyName];            }        }        else {            //其他類型        }    }    free(arrPropertys);    return myObj;}

4、字典中包含一些iOS不能用的字段

有時候接口返回的數(shù)據(jù)中有id等iOS中和關(guān)鍵字重合的字段, 這個時候我們需要將id手動映射到模型中對應(yīng)的屬性中我們在剛剛創(chuàng)建的協(xié)議中在添加一個方法來處理
@protocol YJModelDicTransform <NSObject>@optional/** *  數(shù)組中存儲的類型 * *  @return key --- 屬性名,  value --- 數(shù)組中存儲的類型 */+ (NSDictionary *)yj_objectClassInArray;/** *  替換一些字段 * *  @return key -- 模型中的字段, value --- 字典中的字段 */+ (NSDictionary *)yj_propertykeyReplacedWithValue;@end在model中實現(xiàn)這個方法
+ (NSDictionary *)yj_propertykeyReplacedWithValue{    return @{@"_id":@"id"};}
+ (instancetype)yj_initWithDictionary:(NSDictionary *)dic{    id myObj = [[self alloc] init];    unsigned int outCount;    //獲取類中的所有成員屬性    objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount);    for (NSInteger i = 0; i < outCount; i ++) {        objc_property_t property = arrPropertys[i];        //獲取屬性名字符串        //model中的屬性名        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];        //字典中的屬性名        NSString *newPropertyName;        if ([self respondsToSelector:@selector(yj_propertykeyReplacedWithValue)]) {            newPropertyName = [[self yj_propertykeyReplacedWithValue] objectForKey:propertyName];        }        if (!newPropertyName) {            newPropertyName = propertyName;        }        NSLog(@"屬性名:%@", propertyName);        id propertyValue = dic[newPropertyName];        if (propertyValue == nil) {            continue;        }        //獲取屬性是什么類型的        NSDictionary *dicPropertyType = [self propertyTypeFromProperty:property];        NSString *propertyClassType = [dicPropertyType objectForKey:@"classType"];        NSString *propertyType = [dicPropertyType objectForKey:@"type"];        if ([propertyType isEqualToString:YJClassType_object]) {            if ([propertyClassType isEqualToString:@"NSArray"] || [propertyClassType isEqualToString:@"NSMutableArray"]) {                //數(shù)組類型                if ([self respondsToSelector:@selector(yj_objectClassInArray)]) {                    id propertyValueType = [[self yj_objectClassInArray] objectForKey:propertyName];                    if ([propertyValueType isKindOfClass:[NSString class]]) {                        propertyValue = [NSClassFromString(propertyValueType) yj_initWithArray:propertyValue];                    }                    else {                        propertyValue = [propertyValueType yj_initWithArray:propertyValue];                    }                    if (propertyValue != nil) {                        [myObj setValue:propertyValue forKey:propertyName];                    }                }            }            else if ([propertyClassType isEqualToString:@"NSDictionary"] || [propertyClassType isEqualToString:@"NSMutableDictionary"]) {                //字典類型   不考慮,一般不會用字典,用自定義model            }            else if ([propertyClassType isEqualToString:@"NSString"]) {                //字符串類型                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }            else {                //自定義類型                propertyValue = [NSClassFromString(propertyClassType) yj_initWithDictionary:propertyValue];                if (propertyValue != nil) {                    [myObj setValue:propertyValue forKey:propertyName];                }            }        }        else if ([propertyType isEqualToString:YJClassType_basic]) {            //基本數(shù)據(jù)類型            if ([propertyClassType isEqualToString:@"c"]) {                //bool類型                NSString *lowerValue = [propertyValue lowercaseString];                if ([lowerValue isEqualToString:@"yes"] || [lowerValue isEqualToString:@"true"]) {                    propertyValue = @(YES);                } else if ([lowerValue isEqualToString:@"no"] || [lowerValue isEqualToString:@"false"]) {                    propertyValue = @(NO);                }            }            else {                propertyValue = [[[NSNumberFormatter alloc] init] numberFromString:propertyValue];            }            if (propertyValue != nil) {                [myObj setValue:propertyValue forKey:propertyName];            }        }        else {            //其他類型        }    }    free(arrPropertys);    return myObj;}控制器中
- (void)viewDidLoad {    [super viewDidLoad];    self.title = @"字典轉(zhuǎn)模型";    NSDictionary *dicTest = @{@"id":@"121",                              @"name":@"張三",                              @"phone":@"110",                              @"age":@"10",                              @"user":@{@"userId":@"2"},                              @"arrUsers":@[@{@"userId":@"2"},@{@"userId":@"2"},@{@"userId":@"2"}]};    TestModel *model = [TestModel yj_initWithDictionary:dicTest];    NSLog(@"model-----id:%@, name:%@, phone:%@, address:%@, age:%@, userId:%@, userName:%@", model._id, model.name, model.phone, model.address, @(model.age), model.user.userId, model.user.userName);    [model.arrUsers enumerateObjectsUsingBlock:^(UserModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {        NSLog(@"arrUser----userId:%@", obj.userId);    }];}控制臺打印

2016-12-19 17:17:03.245 YJModelDicTransform[2099:158162] model-----id:121, name:張三, phone:110, address:(null), age:10, userId:2, userName:(null)

2016-12-19 17:17:03.245 YJModelDicTransform[2099:158162] arrUser----userId:2

2016-12-19 17:17:03.245 YJModelDicTransform[2099:158162] arrUser----userId:2

2016-12-19 17:17:03.245 YJModelDicTransform[2099:158162] arrUser----userId:2

到此,基本完成了字典轉(zhuǎn)模型的功能。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 德格县| 夏河县| 汉寿县| 玉门市| 襄樊市| 麻城市| 静安区| 大方县| 察哈| 邢台市| 云霄县| 墨脱县| 霞浦县| 靖西县| 迁西县| 宣城市| 平阳县| 定边县| 乐安县| 大理市| 延边| 峨眉山市| 新蔡县| 阳原县| 米易县| 莱州市| 曲阳县| 新兴县| 喀喇| 海丰县| 玉田县| 东乡族自治县| 苍溪县| 左云县| 遂昌县| 金昌市| 公安县| 永吉县| 蕲春县| 炉霍县| 壤塘县|