runtime與字典轉模型

設計模型

  • 模型屬性,通常需要跟字典中的key一一對應秩铆,一個一個的生成模型屬性,很慢
  • 我們提供一個字典分類灯变,專門根據(jù)字典生成對應的屬性字符串殴玛。
#import "NSDictionary+PropertyCode.h"

// isKindOfClass:判斷是否是當前類或者它的子類

@implementation NSDictionary (PropertyCode)
- (void)createPropertyCode
{
    NSMutableString *strM = [NSMutableString string];
    /*
        解析字典,生成對應屬性代碼
        1.遍歷字典,取出所有key,每個key對應一個屬性代碼
     
     */
    [self enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull value, BOOL * _Nonnull stop) {
        NSLog(@"%@ %@",key,[value class]);
        

        NSString *code = nil;
        if ([value isKindOfClass:[NSString class]]) {
            // NSString
            code = [NSString stringWithFormat:@"@property (nonatomic ,strong) NSString *%@;",key];
            
        } else if ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){
            //    Bool
            code = [NSString stringWithFormat:@"@property (nonatomic ,assign) BOOL %@;",key];
        }else if ([value isKindOfClass:[NSNumber class]]){
            //    NSInteger
            code = [NSString stringWithFormat:@"@property (nonatomic ,assign) NSInteger %@;",key];
        }else if ([value isKindOfClass:[NSArray class]]){
            //    NSArray
            code = [NSString stringWithFormat:@"@property (nonatomic ,strong) NSArray *%@;",key];
        }else if ([value isKindOfClass:[NSDictionary class]]){
            //    NSDictionary
            code = [NSString stringWithFormat:@"@property (nonatomic ,strong) NSDictionary *%@;",key];
            
        }
        

         // 獲取所有key
        [strM appendFormat:@"\n%@\n",code];
       
    }];
    
    NSLog(@"%@",strM);
    
}
@end

字典轉模型

方式一:KVC

  • 弊端:必須保證,模型中的屬性和字典中的key一一對應
  • 如果不一致添祸,就會調(diào)用setValue:forUndefinedKey:報key
    找不到的錯滚粟。
  • 解決:重寫對象的setValue:forUndefinedKey: ,把系統(tǒng)的方法覆蓋刃泌, 就能繼續(xù)使用KVC凡壤,字典轉模型了
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{

}

方式二:Runtime

  • 思路:利用運行時署尤,遍歷模型中所有屬性,根據(jù)模型的屬性名亚侠,去字典中查找key曹体,取出對應的值,給模型的屬性賦值盖奈。
  • 步驟:提供一個NSObject分類混坞,專門字典轉模型,以后所有模型都可以通過這個分類轉钢坦。
    • 詳細步驟:見代碼
#import <Foundation/Foundation.h>

@protocol ModelDelegate <NSObject>

@optional
// 提供一個協(xié)議究孕,只要準備這個協(xié)議的類,都能把數(shù)組中的字典轉模型
爹凹、厨诸、用在三級數(shù)組轉換
+ (NSDictionary *)arrayContainModelClass;

@end
@interface NSObject (Item)

// 字典轉模型
+ (instancetype)objectWithDict:(NSDictionary *)dict;

@end
#import "NSObject+Item.h"

#import <objc/message.h>
/*
* 把字典中所有value給模型中屬性賦值,
* KVC:遍歷字典中所有key,去模型中查找
* Runtime:根據(jù)模型中屬性名去字典中查找對應value,如果找到就給模型的屬性賦值.
*/
@implementation NSObject (Item)
// 字典轉模型
+ (instancetype)objectWithDict:(NSDictionary *)dict
{
    // 創(chuàng)建對應模型對象
    id objc = [[self alloc] init];
    
    
    unsigned int count = 0;
    
    // 1.獲取成員屬性數(shù)組
    Ivar *ivarList = class_copyIvarList(self, &count);
    
    // 2.遍歷所有的成員屬性名,一個一個去字典中取出對應的value給模型屬性賦值
    for (int i = 0; i < count; i++) {
        
        // 2.1 獲取成員屬性
        Ivar ivar = ivarList[i];
        
        // 2.2 獲取成員屬性名 C -> OC 字符串
       NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        
        // 2.3 _成員屬性名 => 字典key
        NSString *key = [ivarName substringFromIndex:1];
        
        // 2.4 去字典中取出對應value給模型屬性賦值
        id value = dict[key];
        
        
        // 獲取成員屬性類型
        NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        
        // 二級轉換,字典中還有字典,也需要把對應字典轉換成模型
        //
        // 判斷下value,是不是字典
        if ([value isKindOfClass:[NSDictionary class]] && ![ivarType containsString:@"NS"]) { //  是字典對象,并且屬性名對應類型是自定義類型
            // user User
           
            // 處理類型字符串 @\"User\" -> User
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
            // 自定義對象,并且值是字典
            // value:user字典 -> User模型
            // 獲取模型(user)類對象
            Class modalClass = NSClassFromString(ivarType);
            
            // 字典轉模型
            if (modalClass) {
                // 字典轉模型 user
                value = [modalClass objectWithDict:value];
            }
            
            // 字典,user
//            NSLog(@"%@",key);
        }
      
        // 三級轉換:NSArray中也是字典,把數(shù)組中的字典轉換成模型.
        // 判斷值是否是數(shù)組
        if ([value isKindOfClass:[NSArray class]]) {
            // 判斷對應類有沒有實現(xiàn)字典數(shù)組轉模型數(shù)組的協(xié)議
            if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
                
                // 轉換成id類型禾酱,就能調(diào)用任何對象的方法
                id idSelf = self;
                
                // 獲取數(shù)組中字典對應的模型
                NSString *type =  [idSelf arrayContainModelClass][key];
                
                // 生成模型
                Class classModel = NSClassFromString(type);
                NSMutableArray *arrM = [NSMutableArray array];
                // 遍歷字典數(shù)組微酬,生成模型數(shù)組
                for (NSDictionary *dict in value) {
                    // 字典轉模型
                    id model =  [classModel objectWithDict:dict];
                    [arrM addObject:model];
                }
                
                // 把模型數(shù)組賦值給value
                value = arrM;
                
            }
        }

        // 2.5 KVC字典轉模型
        if (value) {
            
            [objc setValue:value forKey:key];
        }
    }
    

    // 返回對象
    return objc;
    
}
@end
  • 模型代碼
#import <Foundation/Foundation.h>
#import "NSObject+Item.h"
@class User;
@interface Status : NSObject <ModelDelegate>

@property (nonatomic, strong) NSString *source;

@property (nonatomic, assign) int reposts_count;

@property (nonatomic, strong) NSArray *pic_urls;

@property (nonatomic, strong) NSString *created_at;

@property (nonatomic, assign) int attitudes_count;

@property (nonatomic, strong) NSString *idstr;

@property (nonatomic, strong) NSString *text;

@property (nonatomic, assign) int comments_count;

@property (nonatomic, strong) User *user;

@end

#import "Status.h"

@implementation Status
+ (NSDictionary *)arrayContainModelClass
{
    return @{@"pic_urls" : @"Picture"};
}

@end
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市颤陶,隨后出現(xiàn)的幾起案子颗管,更是在濱河造成了極大的恐慌,老刑警劉巖滓走,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垦江,死亡現(xiàn)場離奇詭異,居然都是意外死亡搅方,警方通過查閱死者的電腦和手機比吭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姨涡,“玉大人衩藤,你說我怎么就攤上這事√纹” “怎么了赏表?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匈仗。 經(jīng)常有香客問我底哗,道長,這世上最難降的妖魔是什么锚沸? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任跋选,我火速辦了婚禮,結果婚禮上哗蜈,老公的妹妹穿的比我還像新娘前标。我一直安慰自己坠韩,他們只是感情好,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布炼列。 她就那樣靜靜地躺著只搁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俭尖。 梳的紋絲不亂的頭發(fā)上氢惋,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音稽犁,去河邊找鬼焰望。 笑死,一個胖子當著我的面吹牛已亥,可吹牛的內(nèi)容都是我干的熊赖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虑椎,長吁一口氣:“原來是場噩夢啊……” “哼震鹉!你這毒婦竟也來了?” 一聲冷哼從身側響起捆姜,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤传趾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泥技,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浆兰,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年零抬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宽涌。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡平夜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卸亮,到底是詐尸還是另有隱情忽妒,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布兼贸,位于F島的核電站段直,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏溶诞。R本人自食惡果不足惜鸯檬,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望螺垢。 院中可真熱鬧喧务,春花似錦赖歌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坎穿,卻和暖如春展父,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玲昧。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工栖茉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酌呆。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓衡载,卻偏偏與公主長得像,于是被迫代替她去往敵國和親隙袁。 傳聞我的和親對象是個殘疾皇子痰娱,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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