iOS 模型動態(tài)映射

iOS 開發(fā)中,一旦涉及到網(wǎng)絡請求,那么數(shù)據(jù)模型就不可少,當然你也可以選擇直接用網(wǎng)絡請求的數(shù)據(jù),通過獲取key的方式來獲取值,但是作為一個開發(fā),我覺得的讓后續(xù)接手的人能夠快速明白你的代碼,方便自己也方便別人。
下面,就來談談動態(tài)映射,針對json格式的返回數(shù)據(jù)。

首先,先分析下思路吧

1.為了一勞永逸,我們需要一個基類,這里我定義了一個基類
GLCoderObject
2.通過什么方式將json格式的數(shù)據(jù)轉(zhuǎn)換為數(shù)據(jù)模型呢?
這里,我選擇了setValuesForKeysWithDictionary來實現(xiàn),直接給模型的屬性賦值

注意:由于模型中可能有的key并不一定需要,或者服務器增加了數(shù)據(jù),那么在執(zhí)行此方法的時候,就會拋出異常,那么怎么解決呢?
通過查看API,我們會發(fā)現(xiàn)一個函數(shù)
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
當key不存在時,會自動調(diào)用上面的這個方法,可以在這個方法中進行處理,通過重寫此方法就可以避免

實現(xiàn)

子類應該怎么定義屬性?屬性應該和json格式返回的數(shù)據(jù)一致,如下

//.h文件
#import "GLCoderObject.h"

@interface DeviceDetailModel : GLCoderObject

@property (nonatomic, copy) NSString *building_id;//樓棟id
@property (nonatomic, copy) NSString *building_name;//樓棟名字
@property (nonatomic, copy) NSString *device_addr;//設備地址
@property (nonatomic, strong) NSArray *pict_file_list;//圖片數(shù)組


@end

//.m文件
#import "DeviceDetailModel.h"
#import "DevicePicListModel.h"

@implementation DeviceDetailModel

- (void)setPict_file_list:(NSArray *)pictfilelist
{
    NSMutableArray *reArray = [NSMutableArray arrayWithCapacity:pictfilelist.count];
    for (NSDictionary *dic in pictfilelist)
    {
        DevicePicListModel*record = [DevicePicListModel modelObjectWithDictionary:dic];
        [reArray addObject:record];
    }
    _pict_file_list = [reArray copy];
}
@end

//=====DevicePicListModel 
//.h文件
#import "GLCoderObject.h"

@interface DevicePicListModel : GLCoderObject

@property (nonatomic,copy) NSString *pict_file_id;//圖片id

@end

//.m文件
#import "DevicePicListModel.h"

@implementation DevicePicListModel

@end

潛在bug

如果在返回的json中,有關鍵字id,description
應當在子類中,重新定義一個屬性,如m_id,m_description,然后子類中重載父類方法

+(id)modelObjectWithDictionary:(NSDictionary *)dict
{
    id obj = [super modelObjectWithDictionary:dict];
    
    [obj setM_id:dict[@"id"] ? : @""];
    
    [obj setM_description:dict[@"description"] ? : @""];
    return obj;
}
貼上基類源碼
//.h文件
#import <Foundation/Foundation.h>

@interface GLCoderObject : NSObject<NSCoding, NSCopying>

//動態(tài)映射 將字典里的數(shù)據(jù) 賦值到模型

+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;

@end

//.m文件

#import "GLCoderObject.h"
#import <objc/runtime.h>

@implementation GLCoderObject

+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
{
    id obj = [[self alloc] init];
    
    [obj setValuesForKeysWithDictionary:dict];
    
    return obj;
}

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

//歸檔
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int count;
    Ivar* ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];
        const char* name = ivar_getName(ivar);
        NSString* strName = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:strName];
        [aCoder encodeObject:value forKey:strName];
    }
    free(ivars);
}

//解檔
- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init])
    {
        unsigned int count;
        Ivar *ivars = class_copyIvarList([self class], &count);
        
        for (int i = 0; i < count; i ++)
        {
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *strName = [NSString stringWithUTF8String:name];
            id value = [aDecoder decodeObjectForKey:strName];
            [self setValue:value forKey:strName];
        }
        free(ivars);
    }
    return self;
}


- (id)copyWithZone:(NSZone *)zone
{
    return nil;
}



/**
 描述信息

 @return 返回描述信息  利于我們在debug 的時候方便查看
 */
- (NSString *)description
{
    return [NSString stringWithFormat:@"%@",[self getObjectData:self]];
}



/**
 將對象轉(zhuǎn)為NSDictionary

 @param obj 對象
 @return 返回的NSDictionary
 */
- (NSDictionary*)getObjectData:(id)obj
{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    unsigned int propsCount;
    objc_property_t *props = class_copyPropertyList([obj class], &propsCount);
    for(int i = 0;i < propsCount; i++)
    {
        objc_property_t prop = props[i];
        
        NSString *propName = [NSString stringWithUTF8String:property_getName(prop)];
        id value = [obj valueForKey:propName];
        if(value == nil)
        {
            value = [NSNull null];
        }
        else
        {
            value = [self getObjectInternal:value];
        }
        
        [dic setObject:value forKey:propName];
    }
    return dic;
}


/**
 針對對象里面屬性的不同屬性 進行轉(zhuǎn)換

 @param obj 對象
 @return 返回
 */
- (id)getObjectInternal:(id)obj
{
    if([obj isKindOfClass:[NSString class]]
       || [obj isKindOfClass:[NSNumber class]]
       || [obj isKindOfClass:[NSNull class]])
    {
        return obj;
    }
    
    if([obj isKindOfClass:[NSArray class]])
    {
        NSArray *objarr = obj;
        NSMutableArray *arr = [NSMutableArray arrayWithCapacity:objarr.count];
        for(int i = 0;i < objarr.count; i++)
        {
            [arr setObject:[self getObjectInternal:[objarr objectAtIndex:i]] atIndexedSubscript:i];
        }
        return arr;
    }
    
    if([obj isKindOfClass:[NSDictionary class]])
    {
        NSDictionary *objdic = obj;
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[objdic count]];
        for(NSString *key in objdic.allKeys)
        {
            [dic setObject:[self getObjectInternal:[objdic objectForKey:key]] forKey:key];
        }
        return dic;
    }
    return [self getObjectData:obj];
}

@end

在上述源碼中,我還用到了歸檔,這在我們緩存的時候可以用到,如果需要用歸檔的方式進行緩存,個人愛好而已。
寫的順序有點亂,因為比較簡單,所以就不貼demo了,以上所有代碼就是一份完整的demo。在使用過程中,感覺還可以,如果有什么不對的,望各位大神多多指教。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • //我所經(jīng)歷的大數(shù)據(jù)平臺發(fā)展史(三):互聯(lián)網(wǎng)時代 ? 上篇http://www.infoq.com/cn/arti...
    葡萄喃喃囈語閱讀 51,683評論 10 200
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,662評論 18 399
  • 我是空氣。瘦削的身影 隱藏在城市的日新月異, 陽光早已將我們忘記,遺失在—— 城市的記憶里。 無人問候,無人關心。...
    小小尋閱讀 506評論 22 11
  • 如今我們看到各地正在興起一波工業(yè)改造熱潮,文化創(chuàng)意產(chǎn)業(yè)蔚然興起,旨在把消費,休閑,娛樂,辦公,旅游,影視等諸多產(chǎn)業(yè)...
    xxt1946閱讀 229評論 0 0

友情鏈接更多精彩內(nèi)容