模型转换工具Mantle, MJExtension, JSONModel的使用和异同

前端之家收集整理的这篇文章主要介绍了模型转换工具Mantle, MJExtension, JSONModel的使用和异同前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

现在大部分的项目都需要将服务器返回的JSON数据转换为Model再使用,手动转换不仅费时费力,还写了一堆重复代码,肯定是不科学的,一般都使用相应的工具来自动转换。目前接触的字典转模型工具有三种,Mantle,MJExtension,JSONModel,虽然他们做的事情都是一样的,但是使用方法区别还是蛮大的,以及在一些细节上的处理也是不同的。

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,152)!important">"sex" : 0,152)!important">"login_date" : "1445136827",152)!important">"phone" : @{  "name" : "小明的iPhone",152)!important">"price" : 5000  }  "books" : @[  "西游记"},152)!important">"三国演义"}  ]  };  }  return _JSONDict; } 

对应模型的特点: 1、有NSNull对象,2、模型里面嵌套模型,3、模型里面有数组,数组里面有模型.

对应的模型如下:

18
19
20
21
22
23
.h typedef NS_ENUM(NSUInteger, Sex) {  SexMale,  SexFemale };  @interface BookForMantle : MTLModel <MTLJSONSerializing> property (nonatomic,210)!important">copy,210)!important">nullable) NSString *name; end  PhoneForMantle : assign) double price; UserForMantle : assign) NSInteger age; Sex sex; strong,210)!important">NSDate *loginDate; PhoneForMantle *phone; NSArray<BookForMantle *> *books; end 
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
m implementation PhoneForMantle  + (JSONKeyPathsByPropertyKey {  return "name",152)!important">"price"}; }  BookForMantle  + ("name"}; }  UserForMantle  // 该map不光是JSON->Model,Model->JSON也会用到 + ("age",152)!important">"sex",152)!important">"loginDate" : "login_date",152)!important">"phone",152)!important">"books"}; }  // 模型里面的模型 + (NSValueTransformer *)phoneTransformer {  return [MTLJSONAdapter dictionaryTransformerWithModelClass:[PhoneForMantle class]]; }  // 模型里面的数组 + (booksTransformer {  arrayTransformerWithModelClass:[BookForMantle // 时间 + (loginDateJSONTransformer {  MTLValueTransformer transformerUsingForwardBlock:^id(timeIntervalSince1970,210)!important">BOOL *success,210)!important">NSError *__autoreleasing *error) {  NSTimeInterval timeInterval = [timeIntervalSince1970 doubleValue];  date = [NSDate dateWithTimeIntervalSince1970:timeInterval];  date;  } reverseBlock:^date,210)!important">timeInterval = date.timeIntervalSince1970;  @(timeInterval).stringValue;  }]; }  end 

对应的解析方法:

10
// 注意: Mantle不会自动转类型,如:String->Int,一旦类型不匹配,直接crash // Json->Model // 该方法调用key-key map方法 self.userForMantle = [modelOfClass:[UserForMantle class] fromJSONDictionary: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 = [JSONDictionaryFromModel:userForMantle nil]; 

JSOMModel的使用

仍旧使用上面的例子,对应的模型如下:

53
54
55
56
57
58
59
60
// BookForJsonModel protocol BookForJsonModel BookForJsonModel : JSONModel BookForJSONModel // 前面是服务器字段,后面是模型属性字段 + (JSONKeyMapper *)keyMapper {  return [[JSONKeyMapper alloc] initWithDictionary:"name"  }]; } end  // PhoneForJSONModel PhoneForJSONModel : PhoneForJSONModel + ("price"  }]; } // UserForJSONModel UserForJSONModel : PhoneForJSONModel *phone; // 注意协议 BookForJSONModel> *UserForJSONModel + ("loginDate",152)!important">"books"  }]; }  // 允许所有字段为空 + (BOOL)propertyIsOptional:(NSString *)propertyName {  YES; }  对应的解析方法

4
// JSON->Model UserForJSONModel *user = [[UserForJSONModel initWithDictionary:// Model->JSON dict = [user toDictionary]; 

JSONModel各方面都挺好的,唯一需要注意的地方是它归档的方式,它不是将对象归档,而是转换成字典再归档。

16
-(instancetype)initWithCoder:(NSCoder *)decoder {  NSString* json = [decoder decodeObjectForKey:"json"];   JSONModelError *error = nil;  self = [self initWithString:json error:&error];  JMLog("%@",[error localizedDescription]);  }  self; }  -(void)encodeWithCoder:(encoder {  [encoder encodeObject:toJSONString forKey:"json"]; } 

MJExtension的使用

这个的使用方式就不介绍了,GitHub上写的非常详细。这里主要说说我在用的项目中时遇到问题及解决方式。情况大致是这样的: 最开始项目中的模型统统继承自BaseModel类,解析方式都是自己挨个手动解析。还自定义了一些譬如时间戳转自定义日期类型的方法。在换到MJExtension时,没法对我们的自定义解析方式进行兼容,全部重写肯定是不现实的,只能做兼容。最后通过阅读MJExtension的源码,找到了一个突破口。在BaseModel里面对MJExtension里面的一个方法使用Method Swizzling进行替换。大致代码如下:

3
BaseModel.h 里面添加一个接口,子类可以覆盖 /// json->模型,转换完成之后调用,以便进行自定义配置。 - (mc_keyValuesDidFinishConvertingToObjectWithData:(id)data; 
28
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:);  swizzledSelector = mc_setKeyValues:Method originalMethod = class_getInstanceMethod(class,210)!important">originalSelector);  swizzledMethod = swizzledSelector);   BOOL success = class_addMethod(originalSelector,210)!important">method_getImplementation(swizzledMethod),210)!important">method_getTypeEncoding(swizzledMethod));  success) {  class_replaceMethod(swizzledSelector,210)!important">originalMethod),210)!important">originalMethod));  } else {  method_exchangeImplementations(originalMethod,210)!important">swizzledMethod);  }  }); }  - (mc_setKeyValues:(keyValues context:(NSManagedObjectContext *)context error:(NSError **)error {  MCDataModel *model = [mc_setKeyValues:context:if ([respondsToSelector:mc_keyValuesDidFinishConvertingToObjectWithData:)]) {  [mc_keyValuesDidFinishConvertingToObjectWithData:keyValues];  }  model; } 

这样在使用MJExtension将模型解析完成之后再调用mc_keyValuesDidFinishConvertingToObjectWithData: 将原始数据传递过去进行自定义配置。就可以很好的与老工程兼容了。

原文链接:https://www.f2er.com/json/289007.html

猜你在找的Json相关文章