iOS開發(fā)之 Runtime模型與字典互轉(zhuǎn)

根據(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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拄氯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子它浅,更是在濱河造成了極大的恐慌译柏,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姐霍,死亡現(xiàn)場離奇詭異鄙麦,居然都是意外死亡,警方通過查閱死者的電腦和手機镊折,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門胯府,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恨胚,你說我怎么就攤上這事骂因。” “怎么了赃泡?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵寒波,是天一觀的道長。 經(jīng)常有香客問我急迂,道長影所,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任僚碎,我火速辦了婚禮猴娩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勺阐。我一直安慰自己卷中,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布渊抽。 她就那樣靜靜地躺著蟆豫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懒闷。 梳的紋絲不亂的頭發(fā)上十减,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天栈幸,我揣著相機與錄音,去河邊找鬼帮辟。 笑死速址,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的由驹。 我是一名探鬼主播芍锚,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蔓榄!你這毒婦竟也來了并炮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤甥郑,失蹤者是張志新(化名)和其女友劉穎逃魄,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澜搅,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嗅钻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了店展。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡秃流,死狀恐怖赂蕴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舶胀,我是刑警寧澤概说,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站嚣伐,受9級特大地震影響糖赔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轩端,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一放典、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧基茵,春花似錦奋构、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至根灯,卻和暖如春径缅,著一層夾襖步出監(jiān)牢的瞬間掺栅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工纳猪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氧卧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓兆旬,卻偏偏與公主長得像假抄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丽猬,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 對于從事 iOS 開發(fā)人員來說宿饱,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,697評論 7 64
  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應用...
    Ryan___閱讀 1,933評論 1 3
  • 很多時候我們需要把從服務器端請求下來的數(shù)據(jù)轉(zhuǎn)成model類,今天就介紹一下如何利用runtime實現(xiàn)字典轉(zhuǎn)模型 1...
    lkkwxy閱讀 4,628評論 7 15
  • 姑娘的傘老是丟脚祟,才學期過半就連丟兩把谬以。但夏天的烈日讓她不得不在丟的那刻決定買把新傘。 這天發(fā)生在姑娘和同學們...
    sueding閱讀 305評論 0 0
  • 1 那天和幾個閨蜜微信群里聊天,說起又快到一年一度的“雙11”了行您,作為網(wǎng)購達人铭乾,該提前備戰(zhàn)了,于是群里熱火朝天地開...
    小確幸來一打閱讀 1,351評論 12 8