IOS模型轉換Mantle, MJExtension, JSONModel總結

現在大部分的項目都需要將服務器返回的JSON數據轉換為Model再使用。罪最原始的辦法就就是使用KVC 方法。
其次就是使用目前常用的字典轉模型工具,Mantle, MJExtension, JSONModel, 雖然他們做的事情都是一樣的,但是使用方法區別還是蠻大的,以及在一些細節上的處理也是不同的。

常用的集中方法
* KVC
* Mantle
* MJExtension
* JSONModel

文檔詳細度:
JSONModel > MJExtension > Mantle
性能:
JSONModel > MJExtension > Mantle

參考文檔:
Mantle、JSONModel、MJExtension性能測試

一、KVC


BSERootNoticeModel.m
#import "BSERootNoticeModel.h"

@implementation BSERootNoticeModel
- (instancetype)initWithDict:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    
}

-(void)setNilValueForKey:(NSString *)key{
    
}
@end
BSERootNoticeModel.h

#import <Foundation/Foundation.h>

@interface BSERootNoticeModel : NSObject
@property(nonatomic,strong)NSString *noticeType;
@property(nonatomic,strong)NSString *content;
@property(nonatomic,strong)NSString *endDate;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end

賦值時使用方法

    BSERootNoticeModel *model = [[BSERootNoticeModel alloc]initWithDict:dic];

要點:

  核心函數
  [self setValuesForKeysWithDictionary:dict]; 
使用KVC 的時候需要注意 在相應的Model類里面需要重寫以下兩個方法,防止閃退。
 -(void)setValue:(id)value forUndefinedKey:(NSString *)key;
 -(void)setNilValueForKey:(NSString *)key;

二、 Mantle 使用

使用Mantle 的Model 需要集成MTLModel 并且實現MTLJSONSerializing 協議。

簡單的例子就不來了,可以直接到Github上面查看,這里上一個比較典型全面的例子。

- (NSDictionary *)JSONDict {
    if (_JSONDict == nil) {
        _JSONDict = @{@"name" : [NSNull null],
                      @"age" : @20,
                      @"sex" : @0,
                      @"login_date" : @"1445136827",
                      @"phone" : @{
                              @"name" : @"小明的iPhone",
                              @"price" : @5000
                      }
                      @"books" : @[
                              @{@"name" : @"西游記"},
                          @{@"name" : @"三國演義"}
                      ]
                      };
    }
    return _JSONDict;
}

對應模型的特點: 1、有NSNull對象, 2、模型里面嵌套模型, 3、模型里面有數組,數組里面有模型.

對應的模型如下:

.h 文件
typedef NS_ENUM(NSUInteger, Sex) {
    SexMale,
    SexFemale
};
@interface BookForMantle : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy, nullable) NSString *name;
@end

@interface PhoneForMantle : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, assign) double price;
@end

@interface UserForMantle : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign)  Sex sex;
@property (nonatomic, strong, nullable) NSDate *loginDate;
@property (nonatomic, strong, nullable) PhoneForMantle *phone;
@property (nonatomic, copy, nullable) NSArray<BookForMantle *> *books;
@end
.m 文件
@implementation PhoneForMantle
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{@"name" : @"name",
             @"price" : @"price"};
}
@end

@implementation BookForMantle
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{@"name" : @"name"};
}
@end

@implementation UserForMantle
// 該map不光是JSON->Model, Model->JSON也會用到
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{@"name" : @"name",
             @"age" : @"age",
             @"sex" : @"sex",
             @"loginDate" : @"login_date",
             @"phone" : @"phone",
             @"books" : @"books"};
}

// 模型里面的模型
+ (NSValueTransformer *)phoneTransformer {
    return [MTLJSONAdapter dictionaryTransformerWithModelClass:[PhoneForMantle class]];
}

// 模型里面的數組
+ (NSValueTransformer *)booksTransformer {
    return [MTLJSONAdapter arrayTransformerWithModelClass:[BookForMantle class]];
}

// 時間 將 NSNumber類型的時間轉換為NSDate類型
+ (NSValueTransformer *)loginDateJSONTransformer {
    return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *timeIntervalSince1970, BOOL *success, NSError *__autoreleasing *error) {
        NSTimeInterval timeInterval = [timeIntervalSince1970 doubleValue];
        NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
        return date;
    } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
        NSTimeInterval timeInterval = date.timeIntervalSince1970;
        return @(timeInterval).stringValue;
    }];
}

@end

對應的解析方法:

// 注意: Mantle不會自動轉類型,如:String->Int, 一旦類型不匹配,直接crash
// Json->Model
// 該方法會調用key-key map方法。
self.userForMantle = [MTLJSONAdapter modelOfClass:[UserForMantle class] fromJSONDictionary:self.JSONDict error:nil];
// 這種方式只是簡單的使用KVC進行賦值。不會調用key-key map方法, 要求屬性和JSON字典中的key名稱相同,否則就crash
//    self.userForMantle = [UserForMantle modelWithDictionary:self.JSONDict error:&error];

// Model -> JSON
// 一旦有屬性為nil, Mantle會轉換成NSNull對象放到JSON字典中,這里有一個坑,使用NSUserDefault存儲這樣的JSON字典時,程序crash,原因是不可以包含NSNull對象。
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:self.userForMantle error:nil];

三、JSOMModel 的使用


仍舊使用上面的例子,對應的模型如下:

// BookForJsonModel
@protocol BookForJsonModel
@end

@interface BookForJsonModel : JSONModel
@property (nonatomic, copy, nullable) NSString *name;
@end

@implementation BookForJSONModel
// 前面是服務器字段,后面是模型屬性字段
+ (JSONKeyMapper *)keyMapper {
    return [[JSONKeyMapper alloc] initWithDictionary:@{
       @"name" : @"name"
    }];
}
@end

// PhoneForJSONModel
@interface PhoneForJSONModel : JSONModel
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, assign) double price;
@end

@implementation PhoneForJSONModel
+ (JSONKeyMapper *)keyMapper {
    return [[JSONKeyMapper alloc] initWithDictionary:@{
       @"name" : @"name",
       @"price" : @"price"
    }];
}
@end

// UserForJSONModel
@interface UserForJSONModel : JSONModel
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign)  Sex sex;
@property (nonatomic, strong, nullable) NSDate *loginDate;
@property (nonatomic, strong, nullable) PhoneForJSONModel *phone;
// 注意協議  model -> model Array 
@property (nonatomic, copy, nullable) NSArray<BookForJSONModel> *books;
@end

@implementation UserForJSONModel
+ (JSONKeyMapper *)keyMapper {
    return [[JSONKeyMapper alloc] initWithDictionary:@{
       @"name" : @"name",
       @"age" : @"age",
       @"sex" : @"sex",
       @"login_date" : @"loginDate",
       @"phone" : @"phone",
       @"books" : @"books"
    }];
}

// 允許所有字段為空
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
    return YES;
}
@end

對應的解析方法

// JSON->Model
UserForJSONModel *user = [[UserForJSONModel alloc] initWithDictionary:self.JSONDict error:nil];
// Model->JSON
NSDictionary *dict = [user toDictionary];

JSONModel各方面都挺好的,唯一需要注意的地方是它歸檔的方式, 它不是將對象歸檔,而是轉換成字典再歸檔。

-(instancetype)initWithCoder:(NSCoder *)decoder{
    NSString* json = [decoder decodeObjectForKey:@"json"];
    JSONModelError *error = nil;
    self = [self initWithString:json error:&error];
    if (error) {
        JMLog(@"%@",[error localizedDescription]);
    }
    return self;
}

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.toJSONString forKey:@"json"];//將對象轉換成json字符串再歸檔
}

四、MJExtension的使用


MJExtension 不再詳細介紹,大家可以直接看github readme文件已經介紹的很詳細

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,996評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,316評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,406評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,128評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,524評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,759評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,310評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,065評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,249評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,479評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,909評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,140評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,984評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,228評論 2 375

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,156評論 4 61
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協議。它實...
    香橙柚子閱讀 24,006評論 8 183
  • 隱密的英雄 從生到死只是人名 藏身于山河 銘刻于文字 被忽略的生命 被吹干的春青 用滿頭白發守護信仰 用熱血點燃春...
    九月公子閱讀 271評論 0 3
  • 今天的這幅圖其實是有趣的。在給我這幅畫的時候,案主就不斷強調自己不會畫,畫技不好,當他告訴我房子是兩層,而人物是走...
    周米啊閱讀 215評論 0 0
  • 你在你的舞臺你自己的驕傲和美麗中舞蹈 我在你的舞臺外寂靜的黑暗中沉默 我曾愿用盡我有限的時光 就如此的凝視,凝視,...
    靈魂行走閱讀 642評論 0 1