無標(biāo)題文章

Question

通常我們用Objective-C寫的模型層遇到了什么問題蝇裤?
在開發(fā)過程中月劈,我們常常會從服務(wù)端獲取數(shù)據(jù)台舱,數(shù)據(jù)通常是JSON格式。 比較常見的做法是把JSON數(shù)據(jù)轉(zhuǎn)為Model對象付呕,這樣我們可以從Model對象的屬性讀取數(shù)據(jù)。
如:
1廓八、我們每次都要通過-initWithDictionarty:(NSDictionary *)dict解析json數(shù)據(jù)锅很,把值一個一個賦值給MODEL對象,經(jīng)常還會出現(xiàn)[[obj objectForKey:@“KEY”] objectAtIndex:index] objectForKey:@“”]這種層次比較深的遍歷多望,層次關(guān)系也要小心處理嫩舟,比較容易出錯。
或者即使多了一層封裝:

    _userAuthCode = authCode ? authCode : @"";
    _userAuthToken = token ? token : @"";
    _userUid = getStringInDict(jsonObject, @"uid");
    _pauth = getStringInDict(jsonObject, @"pauth");
    NSDictionary *info = getDictionaryInDict(jsonObject, @"info");
    _userUsername = getStringInDict(info, @"username");
    _userSex = getStringInDict(info, @"sex");

但是一樣還要繁瑣處理怀偷。
2家厌、如果遇到服務(wù)端返回的類型不是確定的,更是蛋疼椎工;有時(shí)候說是一個NSString饭于,但是卻給了個NSNumber,還有NSDate類型晋渺,給了NString類型镰绎,我們必須增加一些本來可以沒有的判空∧疚鳎看到這么多if else就煩躁了畴栖。。

self.startKey = getStringInDict(result,@"startKey");
if (self.startKey == nil) {
  if (getIntInDict(result, @"startKey") == 0) {
   self.startKey = @"";
  }else{
   self.startKey = [NSString stringWithFormat:@"%d",getIntInDict(result,@"startKey")];
  }
}

3八千、還有就是接口出了問題吗讶,返回了NSNull燎猛,假設(shè)沒有做好處理,還有可以就Crash.
4照皆、還有Model—>Json
5重绷、序列化歸檔問題

What:

mantleTitle
Mantle是一個用于簡化Cocoa或Cocoa Touch程序中model層的第三方庫。通常我們的應(yīng)該中都會定義大量的model來表示各種數(shù)據(jù)結(jié)構(gòu)膜毁,而這些model的初始化和編碼解碼都需要寫大量的代碼昭卓。

Mantle的優(yōu)點(diǎn)在于能夠大大地簡化這些代碼。是iOS和Mac平臺下基于Objective-C編寫的一個簡單高效的模型層框架瘟滨。
??Mantle源碼中最主要的內(nèi)容包括:

  • MTLModel類:通常是作為我們的Model的基類候醒,該類提供了一些默認(rèn)的行為來處理對象的初始化和歸檔操作,同時(shí)可以獲取到對象所有屬性的鍵值集合杂瘸。
  • MTLJSONAdapter類:用于在MTLModel對象和JSON字典之間進(jìn)行相互轉(zhuǎn)換倒淫,相當(dāng)于是一個適配器。
  • MTLJSONSerializing協(xié)議:需要與JSON字典進(jìn)行相互轉(zhuǎn)換的MTLModel的子類都需要實(shí)現(xiàn)該協(xié)議败玉,以方便MTLJSONApadter對象進(jìn)行轉(zhuǎn)換敌土。

##Use:
首先,看看Mantle的文件結(jié)構(gòu)运翼,文件還是蠻多的返干,不過常用的就那幾個。MTDModel南蹂、MTLJSONAdapter

mantleTitle

TDModel

要使用的Model都必須繼承MTDModel

初始化

MTLModel默認(rèn)的初始化方法-init并沒有做什么事情犬金,只是調(diào)用了下[super init]。而同時(shí)六剥,它提供了一個另一個初始化方法:

- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;

其中參數(shù)dictionaryValue是一個字典晚顷,它包含了用于初始化對象的key-value對。我們來看下它的具體實(shí)現(xiàn):

- (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
    ...
    for (NSString *key in dictionary) {
        // 1. 將value標(biāo)記為__autoreleasing疗疟,這是因?yàn)樵贛TLValidateAndSetValue函數(shù)中该默,
        //    可以會返回一個新的對象存在在該變量中
        __autoreleasing id value = [dictionary objectForKey:key];
        // 2. value如果為NSNull.null,會在使用前將其轉(zhuǎn)換為nil
        if ([value isEqual:NSNull.null]) value = nil;
        // 3. MTLValidateAndSetValue函數(shù)利用KVC機(jī)制來驗(yàn)證value的值對于key是否有效策彤,
        //    如果無效栓袖,則使用使用默認(rèn)值來設(shè)置key的值。
        //    這里同樣使用了對象的KVC特性來將value值賦值給model對應(yīng)于key的屬性店诗。
        //    有關(guān)MTLValidateAndSetValue的實(shí)現(xiàn)可參考源碼裹刮,在此不做詳細(xì)說明。
        BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
        if (!success) return nil;
    }
    ...
}

子類可以重寫該方法庞瘸,可以在設(shè)置完對象的屬性后做進(jìn)一步的處理或初始化工作捧弃,記住:應(yīng)該通過super來調(diào)用父類的實(shí)現(xiàn)**。

游戲盒的例子

h:
#import <Mantle/Mantle.h>

@interface MTDCommonGameListModel : MTLModel<MTLJSONSerializing>
@property (nonatomic,strong) NSString*  gameId;
@property (nonatomic) int               star;
@property (nonatomic) BOOL              hasVideo;
@property (nonatomic) MTDGameDownloadUrlType downloadType;
@property (nonatomic,strong) NSDate*    date;
@property (nonatomic,strong) NSString*  imageUrl;
@property (nonatomic,strong) SubModel*  subModel;
…
m:
#import "MTDCommonGameListModel.h"

@implementation MTDCommonGameListModel

+ (NSDictionary *)JSONKeyPathsByPropertyKey{
    return @{
         @"gameId":@"id",
         @"star":@"star",
         @"hasVideo":@"hasVideo",
         @"downloadType":@"downloadType",
     @"date":@"date”,
         @"imageUrl":@"img",
         @"subModel":@"subModel"
    };
    
}
//服務(wù)端返回的類型兼容 gameId可支持服務(wù)端返回 字符串或數(shù)值類型
+ (NSValueTransformer *)gameIdJSONTransformer {
    return [MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError *__autoreleasing *error) {
        return [value stringValue];
    }];
}
//枚舉類型映射
+ (NSValueTransformer *)stateJSONTransformer {
    return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{                                                @"Others": @(MTDGameDownloadUrlTypeOthers),                                                                      @"Itunes": @(MTDGameDownloadUrlTypeItunes),                                                                  @"ShortLink": @(MTDGameDownloadUrlTypeShortLink)
 }];
}
//date
+ (NSValueTransformer *)dateJSONTransformer { 
      return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSNumber *dateNum) {
               return [NSDate dateWithTimeIntervalSince1970:dateNum.floatValue];  
 } 
 reverseBlock:^(NSDate *date) {
  return [NSString stringWithFormat:@"%f",[date timeIntervalSince1970]]; 
 }];
}
//Model里面的Model實(shí)現(xiàn)
+ (NSValueTransformer *)subModelJSONTransformer {
    return [MTLJSONAdapter dictionaryTransformerWithModelClass:SubModel.class];
}

- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError *__autoreleasing *)error{
    self = [super initWithDictionary:dictionaryValue error:error];
    if (self == nil) {
        return nil;
    }
    return self;
    
}

如果需要轉(zhuǎn)換的屬性可以增加對應(yīng)的方法违霞,通過運(yùn)行時(shí)處理的嘴办,方法命名規(guī)則是 [屬性JSONTransformer],對這個屬性進(jìn)行賦值時(shí)會調(diào)用這個方法先進(jìn)行轉(zhuǎn)換。
當(dāng)JSON數(shù)據(jù)里有NSNull的類型時(shí)买鸽,我們不用做任何處理涧郊,會自動將該屬性置為nil;

Model里面的Model實(shí)現(xiàn)

  • (NSValueTransformer *)subModelJSONTransformer {
    return [MTLJSONAdapter dictionaryTransformerWithModelClass:subModel.class];
    }

reverseBlock model —>JSON

reverseBlock是干什么的呢眼五? 當(dāng)要把Model轉(zhuǎn)換回JSON數(shù)據(jù)時(shí)妆艘,如果設(shè)置了返回值,那么會將NSDate轉(zhuǎn)回NSNumber返回JSON數(shù)據(jù)弹砚。
我們可以調(diào)用 MTLJSONAdapter的

+ (NSDictionary *)JSONDictionaryFromModel:<#(id<MTLJSONSerializing>)#> error:<#(NSError *__autoreleasing *)#>;

方法將一個Model實(shí)例轉(zhuǎn)回JSON數(shù)據(jù)双仍。

合并對象

- (void)mergeValueForKey:(NSString *)key fromModel:(MTLModel *)model;

該方法將當(dāng)前對象指定的key屬性的值與model參數(shù)對應(yīng)的屬性值按照指定的規(guī)則來進(jìn)行合并,這種規(guī)則由我們自定義的-mergeFromModel:方法來確定桌吃。如果我們的子類中實(shí)現(xiàn)了-mergeFromModel:方法,則會調(diào)用它苞轿;如果沒有找到茅诱,且model不為nil,則會用model的屬性的值來替代當(dāng)前對象的屬性的值搬卒。具體實(shí)現(xiàn)如下:

- (void)mergeValueForKey:(NSString *)key fromModel:(MTLModel *)model {
    NSParameterAssert(key != nil);
    // 1. 根據(jù)傳入的key拼接"mergeFromModel:"字符串瑟俭,并從該字符串中獲取到對應(yīng)的selector
    //    如果當(dāng)前對象沒有實(shí)現(xiàn)-mergeFromModel:方法,且model不為nil契邀,則用model的屬性值
    //    替代當(dāng)前對象的屬性值
    //
    //    MTLSelectorWithCapitalizedKeyPattern函數(shù)以C語言的方式來拼接方法字符串摆寄,具體實(shí)現(xiàn)請
    //    參數(shù)源碼,在此不詳細(xì)說明
    SEL selector = MTLSelectorWithCapitalizedKeyPattern("merge", key, "FromModel:");
    if (![self respondsToSelector:selector]) {
        if (model != nil) {
            [self setValue:[model valueForKey:key] forKey:key];
        }
        return;
    }
    // 2. 通過NSInvocation方式來調(diào)用對應(yīng)的-mergeFromModel:方法坯门。
     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:  [self methodSignatureForSelector:selector]];
     invocation.target = self;
     invocation.selector = selector;
     [invocation setArgument:&model atIndex:2];
     [invocation invoke];
 }

此外微饥,MTLModel還提供了另一個方法來合并兩個對象所有的屬性值,即:

 - (void)mergeValuesForKeysFromModel:(MTLModel *)model;

需要注意的是model必須是當(dāng)前對象所屬類或其子類古戴。

<NSCoding>, <NSCopying>, -isEqual:和-hash

在你的子類里面生命屬性欠橘,MTLModel可以提供這些方法的默認(rèn)實(shí)現(xiàn)

Mantle配合歸檔

MTLModel默認(rèn)實(shí)現(xiàn)了 NSCoding協(xié)議,可以利用NSKeyedArchiver方便的對對象進(jìn)行歸檔和解檔现恼。

Mantle配合Core Data

….這個后續(xù)有時(shí)間再補(bǔ)充肃续,目前還沒整理

##****參考:
https://github.com/mantle/mantle
https://segmentfault.com/a/1190000003882034
http://www.reibang.com/p/937266eb6635

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叉袍,隨后出現(xiàn)的幾起案子始锚,更是在濱河造成了極大的恐慌,老刑警劉巖喳逛,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞧捌,死亡現(xiàn)場離奇詭異,居然都是意外死亡艺配,警方通過查閱死者的電腦和手機(jī)察郁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門衍慎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人皮钠,你說我怎么就攤上這事稳捆。” “怎么了麦轰?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵乔夯,是天一觀的道長。 經(jīng)常有香客問我款侵,道長末荐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任新锈,我火速辦了婚禮甲脏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妹笆。我一直安慰自己块请,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布拳缠。 她就那樣靜靜地躺著墩新,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窟坐。 梳的紋絲不亂的頭發(fā)上海渊,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音哲鸳,去河邊找鬼臣疑。 笑死,一個胖子當(dāng)著我的面吹牛帕胆,可吹牛的內(nèi)容都是我干的朝捆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼懒豹,長吁一口氣:“原來是場噩夢啊……” “哼芙盘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起脸秽,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤儒老,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后记餐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驮樊,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了囚衔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挖腰。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖练湿,靈堂內(nèi)的尸體忽然破棺而出猴仑,到底是詐尸還是另有隱情,我是刑警寧澤肥哎,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布辽俗,位于F島的核電站,受9級特大地震影響篡诽,放射性物質(zhì)發(fā)生泄漏崖飘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一杈女、第九天 我趴在偏房一處隱蔽的房頂上張望朱浴。 院中可真熱鬧,春花似錦达椰、人聲如沸赊琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至板丽,卻和暖如春呈枉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背埃碱。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工猖辫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砚殿。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓啃憎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親似炎。 傳聞我的和親對象是個殘疾皇子辛萍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評論 0 9
  • 【2017年最新】? iOS面試題及答案 設(shè)計(jì)模式是什么羡藐? 你知道哪些設(shè)計(jì)模式贩毕,并簡要敘述? 設(shè)計(jì)模式是一種編碼經(jīng)...
    紫色冰雨閱讀 598評論 0 1
  • MVC 具有什么樣的優(yōu)勢仆嗦,各個模塊之間怎么通信辉阶,比如點(diǎn)擊 Button 后 怎么通知 Model?[iOS] MV...
    Lost_693d閱讀 149評論 0 1
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,216評論 0 4
  • 距離林宥嘉微博求婚丁文琪過去好幾天了垃僚。直到現(xiàn)在才談這個話題,似乎有點(diǎn)晚规辱,但其實(shí)有一些情緒在知道這個熱門的時(shí)候就已經(jīng)...
    薰微之戀閱讀 488評論 0 3