Mantle,JSONModel,MJExtension,YYModel的比较
把JSON数据转换为模型,其他的不多说,且看下面分解。
1.Mantle的使用
Mantle
上面介绍的很详细,具体其他用法自行查看。
基本步骤:
1.下载Mantle
2.创建model时候必须继承:MTLModel
3.model必须实现协议:MTLJSONSerializing
4.重写协议的一个方法:
//使用Mantle必须实现的协议 KVO的形式
+(NSDictionary *)JSONKeyPathsByPropertyKey
5.如果model里面属性有嵌套model 或者 属性需要做转换等就实现
+(NSValueTransformer *)JSONTransformerForKey:(NSString *)key
6.映射model主要涉及的类:MTLJSONAdapter
基本原理:
1.获取 model 的属性--> JSONKeyPath 映射字典
2.获取 model 的属性列表
3.根据 model 的方法给网络请求中返回的 JSON 字典中的 value 做值类型转化操作
4.使用 KVC 把值赋给 model 的属性,完成操作
测试API
如果你打开了,那数据基本上就是这样,仅供测试使用,无其他用途。
使用火狐浏览器打开如下:
(1).Mantle 要求所有的 Model 都要继承于 MTLModel 并实现 MTLJSONSerializing 协议
MantleModel.h
@class MantleDataModel,MantleFeedModel,MantleDislikeModel,MantleCommentCountModel,MantlePicsModel,MantleListModel;
@protocol MantleFeedModel
@end
@protocol MantleDislikeModel
@end
@protocol MantleListModel
@end
@interface MantleModel : MTLModel
@property (nonatomic,assign)int status;
@property (nonatomic,copy)NSString *resTime;
@property (nonatomic,copy)NSString *uni;
@property (nonatomic,copy)NSString *localUni;
@property (nonatomic,strong)MantleDataModel *data;
@end
@interface MantleDataModel : MTLModel
@property (nonatomic,assign)NSInteger isIntro;
@property (nonatomic,copy)NSString *feedDownType;
@property (nonatomic,assign)NSInteger feedLastIndex;
@property (nonatomic,strong)NSArray *feed;
@property (nonatomic,copy)NSString *downText;
@property (nonatomic,copy)NSString *lastTimestampString;
@end
@interface MantleFeedModel : MTLModel
@property (nonatomic,copy)NSString *newsId;
@property (nonatomic,copy)NSString *longTitle;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *source;
@property (nonatomic,copy)NSString *link;
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *kpic;
@property (nonatomic,copy)NSString *intro;
@property (nonatomic,copy)NSString *pubDate;
@property (nonatomic,assign)NSInteger interestSwitch;
@property (nonatomic,strong)NSArray *dislikeTags;
@property (nonatomic,copy)NSString *commentId;
@property (nonatomic,assign)NSInteger comment;
@property (nonatomic,strong)MantleCommentCountModel *commentCountInfo;
@property (nonatomic,copy)NSString *feedShowStyle;
@property (nonatomic,copy)NSString *category;
@property (nonatomic,strong)MantlePicsModel *pics;
@property (nonatomic,copy)NSString *recommendInfo;
@property (nonatomic,copy)NSString *articlePubDate;
@end
@interface MantleDislikeModel : MTLModel
@property (nonatomic,assign)NSInteger commentStatus;
@property (nonatomic,assign)NSInteger qreply;
@property (nonatomic,assign)NSInteger show;
@property (nonatomic,assign)NSInteger all;
@property (nonatomic,assign)NSInteger praise;
@property (nonatomic,assign)NSInteger dispraise;
@end
@interface MantleCommentCountModel : MTLModel
@property (nonatomic,assign)NSInteger commentStatus;
@property (nonatomic,assign)NSInteger qreply;
@property (nonatomic,assign)NSInteger show;
@property (nonatomic,assign)NSInteger all;
@property (nonatomic,assign)NSInteger praise;
@property (nonatomic,assign)NSInteger dispraise;
@end
@interface MantlePicsModel : MTLModel
@property (nonatomic,strong)NSArray *list;
@property (nonatomic,assign)NSInteger total;
@end
@interface MantleListModel : MTLModel
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *alt;
@property (nonatomic,copy)NSString *kpic;
@end
MantleModel.m
@implementation MantleModel
//必须实现
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"status":@"status",
@"resTime":@"resTime",
@"uni":@"uni",
@"localUni":@"localUni",
@"data":@"data"};
}
// 模型里面的模型
+ (NSValueTransformer *)dataTransformer {
return [MTLJSONAdapter dictionaryTransformerWithModelClass:MantleDataModel.class];
}
//实现类似+JSONTransformer的方法,来指定某个属性从字典里面取值后的类型(或怎么取值):
//SEL selector = MTLSelectorWithKeyPattern(key, "JSONTransformer");
//注意:属性名+JSONTransformer
+ (NSValueTransformer *)resTimeJSONTransformer
{
return [self dateJSONTransformer];
}
//日期格式转换
+ (NSValueTransformer *)dateJSONTransformer
{
return [MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError *__autoreleasing *error) {
if (success) {
NSTimeInterval secs = [value doubleValue];
return [NSDate dateWithTimeIntervalSince1970:secs];
}else {
return @([value timeIntervalSince1970]);
}
}];
}
@end
@implementation MantleDataModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"isIntro":@"isIntro",
@"feedDownType":@"feedDownType",
@"feedLastIndex":@"feedLastIndex",
@"feed":@"feed",
@"downText":@"downText",
@"lastTimestamp":@"lastTimestamp"
};
}
// 模型里面的数组
+ (NSValueTransformer *)feedTransformer {
return [MTLJSONAdapter arrayTransformerWithModelClass:MantleFeedModel.class];
}
@end
@implementation MantleFeedModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
return mapping;
}
@end
@implementation MantleDislikeModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
return mapping;
}
@end
@implementation MantleCommentCountModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
return mapping;
}
@end
@implementation MantlePicsModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
return mapping;
}
@end
@implementation MantleListModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
return mapping;
}
@end
(2).简单说明:
对JSONKeyPathsByPropertyKey上面写了两种,其中的MantleDataModel你可以利用JSONKeyPathsByPropertyKey把所有属性按字典列出来:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"isIntro":@"isIntro",
@"feedDownType":@"feedDownType",
@"feedLastIndex":@"feedLastIndex",
@"feed":@"feed",
@"downText":@"downText",
@"lastTimestamp":@"lastTimestamp"
};
}
或许你也可以直接写成这样:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
mapping[@"lastTimestampString"] = @"lastTimestamp";
return mapping;
}
利用属性名+JSONTransformer,对于dateJSONTransformer其中简单进行日期转换。
+ (NSValueTransformer *)dateJSONTransformer
{
return [MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError *__autoreleasing *error) {
if (success) {
NSTimeInterval secs = [value doubleValue];
return [NSDate dateWithTimeIntervalSince1970:secs];
}else {
return @([value timeIntervalSince1970]);
}
}];
}
进行关键字替换:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
NSMutableDictionary *mapping = [[NSDictionary mtl_identityPropertyMapWithModel:self] mutableCopy];
mapping[@"lastTimestampString"] = @"lastTimestamp";
return mapping;
}
当你的 Model 里的所有属性的名字和 JSON 里的所有 key 的名字完全相同的时候,你就可以用这个方法直接生成一个 NSDictionary, 直接返回:
比如这个:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"status":@"status",
@"resTime":@"resTime",
@"uni":@"uni",
@"localUni":@"localUni",
@"data":@"data"};
}
你也可以直接这样:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return [NSDictionary mtl_identityPropertyMapWithModel:self];
}
(3)其他
注意: 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];
优点:
1.修改字段映射时相当简便
2.扩展时相对方便
3.可以实现更多复杂的映射关系和数值转换
4.实现了NSCopying和NSCoding协议,可以轻松序列化
缺点:
1.基于运行时属性映射,对性能有一定影响
2.有部分容错处理需要自行解决
其他等等可以自行查看Mantle
2.JSONModel
JSONModel
【对应上面测试API,数据仅供测试使用】:
(1). 所有Model类继承于JSONModel
JSONModel.h
@class dataModel,commentCountModel,picsModel;
@protocol feedModel
@end
@protocol dislikeModel
@end
@protocol commentCountModel
@end
@protocol picsModel
@end
@protocol listModel
@end
@interface BaseJsonModel : JSONModel
@property (nonatomic,assign)int status;
@property (nonatomic,copy)NSString *resTime;
@property (nonatomic,copy)NSString *uni;
@property (nonatomic,copy)NSString *localUni;
@property (nonatomic,strong)dataModel *data;
@end
@interface dataModel : JSONModel
@property (nonatomic,assign)NSInteger isIntro;
@property (nonatomic,copy)NSString *feedDownType;
@property (nonatomic,assign)NSInteger feedLastIndex;
@property (nonatomic,strong)NSArray*feed;
@property (nonatomic,copy)NSString *downText;
@property (nonatomic,copy)NSString *lastTimestamp;
@end
@interface feedModel : JSONModel
@property (nonatomic,copy)NSString *newsId;
@property (nonatomic,copy)NSString *longTitle;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *source;
@property (nonatomic,copy)NSString *link;
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *kpic;
//@property (nonatomic,copy)NSString *intro;
@property (nonatomic,copy)NSString *des;
@property (nonatomic,copy)NSString *pubDate;
@property (nonatomic,assign)NSInteger interestSwitch;
@property (nonatomic,strong)NSArray *dislikeTags;
@property (nonatomic,copy)NSString *commentId;
@property (nonatomic,assign)NSInteger comment;
@property (nonatomic,strong)commentCountModel *commentCountInfo;
@property (nonatomic,copy)NSString *feedShowStyle;
@property (nonatomic,copy)NSString *category;
@property (nonatomic,strong)picsModel *pics;
@property (nonatomic,copy)NSString *recommendInfo;
@end
@interface dislikeModel : JSONModel
@end
@interface commentCountModel : JSONModel
@property (nonatomic,assign)NSInteger commentStatus;
@property (nonatomic,assign)NSInteger qreply;
@property (nonatomic,assign)NSInteger show;
@property (nonatomic,assign)NSInteger all;
@property (nonatomic,assign)NSInteger praise;
@property (nonatomic,assign)NSInteger dispraise;
@end
@interface picsModel : JSONModel
@property (nonatomic,strong)NSArray *list;
@property (nonatomic,assign)NSInteger total;
@end
@interface listModel : JSONModel
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *alt;
@property (nonatomic,copy)NSString *kpic;
@end
JSONModel.m
@implementation BaseJsonModel
@end
@implementation dataModel
@end
@implementation feedModel
+ (JSONKeyMapper *)keyMapper {
return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:
@{
@"des":@"intro",
}];
}
@end
@implementation dislikeModel
@end
@implementation commentCountModel
@end
@implementation picsModel
@end
@implementation listModel
@end
(2).简单说明:
关键值替换
+ (JSONKeyMapper *)keyMapper {
return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:
@{
@"des":@"intro",
}];
}
忽略属性
@property (strong, nonatomic) NSString* qreply;
设置某个字段为可选(为空)
@property (strong, nonatomic) NSString* qreply;
设置所有的属性为可选(为空)
+(BOOL)propertyIsOptional:(NSString*)propertyName
{
return YES;
}
自动把下划线方式的命名转为驼峰命名属性,大小写转换
{
"list_name": wang,
"list_pic" : @"11",
}
生成模型:
@interface ListModel : JSONModel
@property (copy, nonatomic) int listName;
@property (assign, nonatomic) float listPic;
@end
@implementation ListModel
+(JSONKeyMapper*)keyMapper
{
return [JSONKeyMapper mapperFromUnderscoreCaseToCamelCase];
}
其他等等可以自行查看JSONModel
3.YYModel
YYModel
(1).相比上面不用继承
YYJSONModel.h
@class YYJSONDataModel,YYJSONFeedModel;
@interface YYJSONModel : NSObject
@property (nonatomic,assign)int status;
@property (nonatomic,copy)NSString *resTime;
@property (nonatomic,copy)NSString *uni;
@property (nonatomic,copy)NSString *localUni;
@property (nonatomic,strong)YYJSONDataModel *data;
@end
@interface YYJSONDataModel : NSObject
@property (nonatomic,assign)NSInteger isIntro;
@property (nonatomic,copy)NSString *feedDownType;
@property (nonatomic,assign)NSInteger feedLastIndex;
@property (nonatomic,strong)NSArray *feed;
@property (nonatomic,copy)NSString *downText;
@property (nonatomic,copy)NSString *lastTimestamp;
@end
@interface YYJSONFeedModel : NSObject
@property (nonatomic,copy)NSString *newsId;
@property (nonatomic,copy)NSString *longTitle;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *source;
@property (nonatomic,copy)NSString *link;
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *kpic;
@property (nonatomic,copy)NSString *des;
@property (nonatomic,copy)NSString *pubDate;
@property (nonatomic,assign)NSInteger interestSwitch;
@end
YYJSONModel.m
@implementation YYJSONModel
@end
@implementation YYJSONDataModel
// 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"feed" : @"YYJSONFeedModel" };
/*
**@"feed" : [YYJSONFeedModel class],
@"feed" : YYJSONFeedModel.class,
@"feed" : @"YYJSONFeedModel"
*/
}
@end
@implementation YYJSONFeedModel
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"des":@"intro"};
}
@end
(2).简单说明
json转模型
方法: + (instancetype)yy_modelWithJSON:(id)json;
模型转字符串
方法: - (NSString *)yy_modelToJSONString
字典转模型
方法: + (instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary ;
声明数组、字典或者集合里的元素类型时要重写
方法: + (nullable NSDictionary
*)modelContainerPropertyGenericClass; 字典里的key值与模型的属性值不一致要重复
方法: + (nullable NSDictionary
*)modelCustomPropertyMapper; 下面两者是属性值在两个dic与模型之间的转化方法
方法: - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic ;
方法: - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
你可以把一个或一组 json key (key path) 映射到一个或多个属性。如果一个属性没有映射关系,那默认会使用相同属性名作为映射。
在 json->model 的过程中:如果一个属性对应了多个 json key,那么转换过程会按顺序查找,并使用第一个不为空的值。
在 model->json 的过程中:如果一个属性对应了多个 json key (key path),那么转换过程仅会处理第一个 json key (key path);如果多个属性对应了同一个 json key,则转换过过程会使用其中任意一个不为空的值。
被包含的Model什么都不用做,如果属性名不对应,也要实现映射的方法
“+ (NSDictionary *)modelCustomPropertyMapper”
关键值替换
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"des":@"intro"};
}
黑名单 与 白名单:
@interface User
@property NSString *name;
@property NSUInteger age;
@end
@implementation Attributes
// 如果实现了该方法,则处理过程中会忽略该列表内的所有属性
+ (NSArray *)modelPropertyBlacklist {
return @[@"test1", @"test2"];
}
// 如果实现了该方法,则处理过程中不会处理该列表外的属性。
+ (NSArray *)modelPropertyWhitelist {
return @[@"name"];
}
数据校验与自定义转换
JSON:
{
"name":"Wang",
"timestamp" : 1544564567
}
Model:
@interface User
@property NSString *name;
@property NSDate *putDate;
@end
@implementation User
// 当 JSON 转为 Model 完成后,该方法会被调用。
// 你可以在这里对数据进行校验,如果校验不通过,可以返回 NO,则该 Model 会被忽略。
// 你也可以在这里做一些自动转换不能完成的工作。
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
NSNumber *timestamp = dic[@"timestamp"];
if (![timestamp isKindOfClass:[NSNumber class]]) return NO;
_putDate = [NSDate dateWithTimeIntervalSince1970:timestamp.floatValue];
return YES;
}
// 当 Model 转为 JSON 完成后,该方法会被调用。
// 你可以在这里对数据进行校验,如果校验不通过,可以返回 NO,则该 Model 会被忽略。
// 你也可以在这里做一些自动转换不能完成的工作。
- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic {
if (! _putDate) return NO;
dic[@"timestamp"] = @(n.timeIntervalSince1970);
return YES;
}
容器类属性
@interface YYJSONDataModel : NSObject
@property (nonatomic,assign)NSInteger isIntro;
@property (nonatomic,copy)NSString *feedDownType;
@property (nonatomic,assign)NSInteger feedLastIndex;
@property (nonatomic,strong)NSArray *feed;
@property (nonatomic,copy)NSString *downText;
@property (nonatomic,copy)NSString *lastTimestamp;
@end
// 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"feed" : [YYJSONFeedModel class]};
}
其他等等可以自行查看YYModel
4.MJExtension
MJExtension
(1).MJExtension是一套字典和模型之间互相转换的超轻量级框架
MJExtensionModel.h
@class MJExtensionDataModel,MJExtensionFeedModel;
@interface MJExtensionModel : NSObject
@property (nonatomic,assign)int status;
@property (nonatomic,copy)NSString *resTime;
@property (nonatomic,copy)NSString *uni;
@property (nonatomic,copy)NSString *localUni;
@property (nonatomic,strong)MJExtensionDataModel *data;
@end
@interface MJExtensionDataModel : NSObject
@property (nonatomic,assign)NSInteger isIntro;
@property (nonatomic,copy)NSString *feedDownType;
@property (nonatomic,assign)NSInteger feedLastIndex;
@property (nonatomic,strong)NSArray *feed;
@property (nonatomic,copy)NSString *downText;
@property (nonatomic,copy)NSString *lastTimestamp;
@end
@interface MJExtensionFeedModel : NSObject
@property (nonatomic,copy)NSString *newsId;
@property (nonatomic,copy)NSString *longTitle;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *source;
@property (nonatomic,copy)NSString *link;
@property (nonatomic,copy)NSString *pic;
@property (nonatomic,copy)NSString *kpic;
//@property (nonatomic,copy)NSString *intro;
@property (nonatomic,copy)NSString *des;
@property (nonatomic,copy)NSString *pubDate;
@property (nonatomic,assign)NSInteger interestSwitch;
@end
MJExtensionModel.m
@implementation MJExtensionModel
@end
@implementation MJExtensionDataModel
+ (NSDictionary *)mj_objectClassInArray{
return @{
@"feed" : @"MJExtensionFeedModel",
};
}
@end
@implementation MJExtensionFeedModel
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{@"des":@"intro"};
}
@end
(2).简单说明
MJExtension是一套字典和模型之间互相转换的超轻量级框架
只需要一行代码,就能实现模型的所有属性进行Coding(归档和解档)
JSON --> Model、Core Data Model
JSONString --> Model、Core Data Model
Model、Core Data Model --> JSON
JSON Array --> Model Array、Core Data Model Array
JSONString --> Model Array、Core Data Model Array
Model Array、Core Data Model Array --> JSON Array
还是
其他等等可以自行查看MJExtension
iOS JSON 模型转换库评测
终于结束了。