現(xiàn)在大部分的項(xiàng)目都需要將服務(wù)器返回的JSON數(shù)據(jù)轉(zhuǎn)換為Model再使用假夺。罪最原始的辦法就就是使用KVC 方法烟逊。
其次就是使用目前常用的字典轉(zhuǎn)模型工具济蝉,Mantle, MJExtension, JSONModel, 雖然他們做的事情都是一樣的牡直,但是使用方法區(qū)別還是蠻大的肩碟,以及在一些細(xì)節(jié)上的處理也是不同的漱逸。
常用的集中方法 |
---|
* KVC |
* Mantle |
* MJExtension |
* JSONModel |
文檔詳細(xì)度:
JSONModel > MJExtension > Mantle
性能:
JSONModel > MJExtension > Mantle
參考文檔:
Mantle泪姨、JSONModel、MJExtension性能測(cè)試
一饰抒、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
賦值時(shí)使用方法
BSERootNoticeModel *model = [[BSERootNoticeModel alloc]initWithDict:dic];
要點(diǎn):
核心函數(shù)
[self setValuesForKeysWithDictionary:dict];
使用KVC 的時(shí)候需要注意 在相應(yīng)的Model類(lèi)里面需要重寫(xiě)以下兩個(gè)方法肮砾,防止閃退。
-(void)setValue:(id)value forUndefinedKey:(NSString *)key;
-(void)setNilValueForKey:(NSString *)key;
二袋坑、 Mantle 使用
使用Mantle 的Model 需要集成MTLModel 并且實(shí)現(xiàn)MTLJSONSerializing 協(xié)議仗处。
簡(jiǎn)單的例子就不來(lái)了,可以直接到Github上面查看枣宫,這里上一個(gè)比較典型全面的例子婆誓。
- (NSDictionary *)JSONDict {
if (_JSONDict == nil) {
_JSONDict = @{@"name" : [NSNull null],
@"age" : @20,
@"sex" : @0,
@"login_date" : @"1445136827",
@"phone" : @{
@"name" : @"小明的iPhone",
@"price" : @5000
}
@"books" : @[
@{@"name" : @"西游記"},
@{@"name" : @"三國(guó)演義"}
]
};
}
return _JSONDict;
}
對(duì)應(yīng)模型的特點(diǎn): 1、有NSNull對(duì)象, 2也颤、模型里面嵌套模型, 3洋幻、模型里面有數(shù)組,數(shù)組里面有模型.
對(duì)應(yīng)的模型如下:
.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也會(huì)用到
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"name" : @"name",
@"age" : @"age",
@"sex" : @"sex",
@"loginDate" : @"login_date",
@"phone" : @"phone",
@"books" : @"books"};
}
// 模型里面的模型
+ (NSValueTransformer *)phoneTransformer {
return [MTLJSONAdapter dictionaryTransformerWithModelClass:[PhoneForMantle class]];
}
// 模型里面的數(shù)組
+ (NSValueTransformer *)booksTransformer {
return [MTLJSONAdapter arrayTransformerWithModelClass:[BookForMantle class]];
}
// 時(shí)間 將 NSNumber類(lèi)型的時(shí)間轉(zhuǎn)換為NSDate類(lèi)型
+ (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
對(duì)應(yīng)的解析方法:
// 注意: Mantle不會(huì)自動(dòng)轉(zhuǎn)類(lèi)型翅娶,如:String->Int, 一旦類(lèi)型不匹配文留,直接crash
// Json->Model
// 該方法會(huì)調(diào)用key-key map方法好唯。
self.userForMantle = [MTLJSONAdapter modelOfClass:[UserForMantle class] fromJSONDictionary:self.JSONDict error:nil];
// 這種方式只是簡(jiǎn)單的使用KVC進(jìn)行賦值。不會(huì)調(diào)用key-key map方法, 要求屬性和JSON字典中的key名稱相同燥翅,否則就crash
// self.userForMantle = [UserForMantle modelWithDictionary:self.JSONDict error:&error];
// Model -> JSON
// 一旦有屬性為nil, Mantle會(huì)轉(zhuǎn)換成NSNull對(duì)象放到JSON字典中渠啊,這里有一個(gè)坑,使用NSUserDefault存儲(chǔ)這樣的JSON字典時(shí)权旷,程序crash替蛉,原因是不可以包含NSNull對(duì)象。
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:self.userForMantle error:nil];
三拄氯、JSOMModel 的使用
仍舊使用上面的例子躲查,對(duì)應(yīng)的模型如下:
// BookForJsonModel
@protocol BookForJsonModel
@end
@interface BookForJsonModel : JSONModel
@property (nonatomic, copy, nullable) NSString *name;
@end
@implementation BookForJSONModel
// 前面是服務(wù)器字段,后面是模型屬性字段
+ (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;
// 注意協(xié)議 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
對(duì)應(yīng)的解析方法
// JSON->Model
UserForJSONModel *user = [[UserForJSONModel alloc] initWithDictionary:self.JSONDict error:nil];
// Model->JSON
NSDictionary *dict = [user toDictionary];
JSONModel各方面都挺好的译柏,唯一需要注意的地方是它歸檔的方式, 它不是將對(duì)象歸檔镣煮,而是轉(zhuǎn)換成字典再歸檔。
-(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"];//將對(duì)象轉(zhuǎn)換成json字符串再歸檔
}
四鄙麦、MJExtension的使用
MJExtension 不再詳細(xì)介紹典唇,大家可以直接看github readme文件已經(jīng)介紹的很詳細(xì)