模型转换工具Mantle, MJExtension, JSONModel的使用和异同
2017-02-27 15:50
459 查看
现在大部分的项目都需要将服务器返回的JSON数据转换为Model再使用,手动转换不仅费时费力,还写了一堆重复代码,肯定是不科学的,一般都使用相应的工具来自动转换。目前接触的字典转模型工具有三种,Mantle, MJExtension, JSONModel, 虽然他们做的事情都是一样的,但是使用方法区别还是蛮大的,以及在一些细节上的处理也是不同的。
简单的例子就不来了,可以直接到Github上面查看,这里上一个比较典型全面的例子。
对应模型的特点: 1、有NSNull对象, 2、模型里面嵌套模型, 3、模型里面有数组,数组里面有模型.
对应的模型如下:
对应的解析方法:
仍旧使用上面的例子,对应的模型如下:
对应的解析方法
JSONModel各方面都挺好的,唯一需要注意的地方是它归档的方式, 它不是将对象归档,而是转换成字典再归档。
这个的使用方式就不介绍了,GitHub上写的非常详细。这里主要说说我在用的项目中时遇到问题及解决方式。情况大致是这样的:
最开始项目中的模型统统继承自BaseModel类,解析方式都是自己挨个手动解析。还自定义了一些譬如时间戳转自定义日期类型的方法。在换到MJExtension时,没法对我们的自定义解析方式进行兼容,全部重写肯定是不现实的,只能做兼容。最后通过阅读MJExtension的源码,找到了一个突破口。在BaseModel里面对MJExtension里面的一个方法使用Method Swizzling进行替换。大致代码如下:
这样在使用MJExtension将模型解析完成之后再调用mc_keyValuesDidFinishConvertingToObjectWithData: 将原始数据传递过去进行自定义配置。就可以很好的与老工程兼容了。
Mantle的使用
简单的例子就不来了,可以直接到Github上面查看,这里上一个比较典型全面的例子。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | - (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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1819 | .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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1819 | .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]]; } // 时间 + (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 |
1 2 3 4 5 6 7 8 9 10 | // 注意: 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的使用
仍旧使用上面的例子,对应的模型如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1819 | // 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; // 注意协议 @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 |
1 2 3 4 | // JSON->Model UserForJSONModel *user = [[UserForJSONModel alloc] initWithDictionary:self.JSONDict error:nil]; // Model->JSON NSDictionary *dict = [user toDictionary]; |
1 2 3 4 5 6 7 8 9 1011 | -(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"]; } |
MJExtension的使用
这个的使用方式就不介绍了,GitHub上写的非常详细。这里主要说说我在用的项目中时遇到问题及解决方式。情况大致是这样的:最开始项目中的模型统统继承自BaseModel类,解析方式都是自己挨个手动解析。还自定义了一些譬如时间戳转自定义日期类型的方法。在换到MJExtension时,没法对我们的自定义解析方式进行兼容,全部重写肯定是不现实的,只能做兼容。最后通过阅读MJExtension的源码,找到了一个突破口。在BaseModel里面对MJExtension里面的一个方法使用Method Swizzling进行替换。大致代码如下:
1 2 3 | BaseModel.h 里面添加一个接口,子类可以覆盖 /// json->模型,转换完成之后调用, 以便进行自定义配置。 - (void)mc_keyValuesDidFinishConvertingToObjectWithData:(id)data; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1819 | BaseModel.m /* 替换方法: - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error; */ + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; SEL originalSelector = @selector(setKeyValues:context:error:); SEL swizzledSelector = @selector(mc_setKeyValues:context:error:); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (success) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } }); } - (instancetype)mc_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error { MCDataModel *model = [self mc_setKeyValues:keyValues context:context error:error]; if ([self respondsToSelector:@selector(mc_keyValuesDidFinishConvertingToObjectWithData:)]) { [self mc_keyValuesDidFinishConvertingToObjectWithData:keyValues]; } return model; } |
相关文章推荐
- 模型转换工具 Mantle, MJExtension, JSONModel 的使用和异同及防崩溃能力比较
- iOS_OC 字典模型转换工具的比较(Mantle和MJExtension和Jsonmodel) 持续更新
- 模型转换工具Mantle, MJExtension, JSONModel的使用和异同
- 网络:YYModel 使用(JSON到模型的转换)
- 使用 Jackson 树模型(tree model) API 处理 JSON
- json和bean的转换工具Jackson ObjectMapper类使用解析
- MJExtension(JSON到数据模型的自动转换)
- Java对象、Json、Xml转换工具Jackson使用
- JSONModel、Mantle、MJExtension、YYModel 等工具的对比
- iOS开发中的使用kvc快速将字典模型转换成model模型。
- 使用python开发json、csv数据格式转换工具
- json和bean的转换工具Jackson ObjectMapper类使用解析
- JSON和模型之间最快捷方便的转换iOS框架:MJExtension
- 使用python开发json、csv数据格式转换工具
- Java对象、Json、Xml转换工具Jackson使用
- MJExtension字典和模型之间相互转换的轻量级框架的使用实例
- MJExtension,JSON数据与Model的转换
- json和bean的转换工具Jackson ObjectMapper类使用解析
- Java对象、Json、Xml转换工具Jackson使用
- json和bean的转换工具Jackson ObjectMapper类使用解析