流弊的JSON数据模型框架
https://github.com/jsonmodel/jsonmodel
版本 1.3.0
如果你喜欢JSONModel,并且使用了它,请你:
-
star一下
-
给我一些反馈. 多谢!
![](https://img.haomeiwen.com/i182380/4c4c9ae0a9d4a9d7.jpg)
JSONModel 是一个能够快速巧妙的创建数据模型的库. 你可以在 iOS or OSX APP中使用它.
JSONModel 自动检查JOSN模型和结构体, 彻底的减少你的代码量.
![](https://img.haomeiwen.com/i182380/72c25bc7e843a8d2.jpg)
添加JSONModel到你的项目中
要求
- 支持持ARC; iOS 5.0+ / OSX 10.7+
- SystemConfiguration.framework
as: 1) 源文件
1.下载JSONModel.zip文件
2.将它拷贝到你的项目中
3.导入SystemConfiguration.framework框架
or 2)使用 CocoaPods
pod 'JSONModel'
如果你想关于CocoaPods了解更多,请参考这个简单的教程.
or 3) 使用 Carthage
在你的项目的Cartfile添加JSONModel:
github "jsonmodel/jsonmodel"
文档
你可以查看在线阅读文档: http://cocoadocs.org/docsets/JSONModel
基本使用
涉想你的JSON数据像这样:
{ "id": "10", "country": "Germany", "dialCode": 49, "isInEurope": true }
- 为你的数据模型创建一个Objective-C的类,继承自JSONModel.
- 将JSON中的keys在.h文件中声明为属性:
#import "JSONModel.h"
@interface CountryModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* country;
@property (strong, nonatomic) NSString* dialCode;
@property (assign, nonatomic) BOOL isInEurope;
@end
在.m文件中不需要做任何事情.
- 用数据初始化你的model:
#import "CountryModel.h"
...
NSString* json = (fetch here JSON from Internet) ...
NSError* err = nil;
CountryModel* country = [[CountryModel alloc] initWithString:json error:&err];
如果传过来的JSON合法,你所定义的所有的属性都会与该JSON的值想对应,甚至JSONModel会尝试去转换数据为你期望的类型,如上所示:
- 转换id,从字符串转换为int
- 只需要拷贝一下country的值
- 转换diaCode,从number转换为字符串
- 最后一个是将isInEurope转换为BOOL属性
所以,你所需要做的就是将你的属性定义为期望的类型.
在线教程
官方网站: http://www.jsonmodel.com
在线文档: http://jsonmodel.com/docs/
傻瓜教程:
举个栗子
命名自动匹配
{
"id": "123",
"name": "Product name",
"price": 12.95
}
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) float price;
@end
@implementation ProductModel
@end
模型嵌套 (模型包含其他模型)
{
"order_id": 104,
"total_price": 13.45,
"product" : {
"id": "123",
"name": "Product name",
"price": 12.95
}
}
@interface OrderModel : JSONModel
@property (assign, nonatomic) int order_id;
@property (assign, nonatomic) float total_price;
@property (strong, nonatomic) ProductModel* product;
@end
@implementation OrderModel
@end
模型集合
{
"order_id": 104,
"total_price": 103.45,
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
}
@protocol ProductModel
@end
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) float price;
@end
@implementation ProductModel
@end
@interface OrderModel : JSONModel
@property (assign, nonatomic) int order_id;
@property (assign, nonatomic) float total_price;
@property (strong, nonatomic) NSArray<ProductModel>* products;
@end
@implementation OrderModel
@end
注意: 尖括号后 <code>NSArray</code> 包含一个协议. 这跟Objective-C原生的泛型不是一个概念. 他们不会冲突, 但对于JSONModel来说,协议必须在一个地方声明.
key映射
{
"order_id": 104,
"order_details" : [
{
"name": "Product#1",
"price": {
"usd": 12.95
}
}
]
}
@interface OrderModel : JSONModel
@property (assign, nonatomic) int id;
@property (assign, nonatomic) float price;
@property (strong, nonatomic) NSString* productName;
@end
@implementation OrderModel
+(JSONKeyMapper*)keyMapper
{
return [[JSONKeyMapper alloc] initWithDictionary:@{
@"order_id": @"id",
@"order_details.name": @"productName",
@"order_details.price.usd": @"price"
}];
}
@end
设置全局键映射(应用于所有model)
[JSONModel setGlobalKeyMapper:[
[JSONKeyMapper alloc] initWithDictionary:@{
@"item_id":@"ID",
@"item.name": @"itemName"
}]
];
设置下划线自动转驼峰
{
"order_id": 104,
"order_product" : @"Product#1",
"order_price" : 12.95
}
@interface OrderModel : JSONModel
@property (assign, nonatomic) int orderId;
@property (assign, nonatomic) float orderPrice;
@property (strong, nonatomic) NSString* orderProduct;
@end
@implementation OrderModel
+(JSONKeyMapper*)keyMapper
{
return [JSONKeyMapper mapperFromUnderscoreCaseToCamelCase];
}
@end
可选属性 (就是说这个属性可以为null或者为空)
{
"id": "123",
"name": null,
"price": 12.95
}
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString<Optional>* name;
@property (assign, nonatomic) float price;
@property (strong, nonatomic) NSNumber<Optional>* uuid;
@end
@implementation ProductModel
@end
忽略属性 (就是完全忽略这个属性)
{
"id": "123",
"name": null
}
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString<Ignore>* customProperty;
@end
@implementation ProductModel
@end
设置所有的属性为可选(所有属性值可以为空)
@implementation ProductModel
+(BOOL)propertyIsOptional:(NSString*)propertyName
{
return YES;
}
@end
使用JSONModel自带的 HTTP 请求
//add extra headers
[[JSONHTTPClient requestHeaders] setValue:@"MySecret" forKey:@"AuthorizationToken"];
//make post, get requests
[JSONHTTPClient postJSONFromURLWithString:@"http://mydomain.com/api"
params:@{@"postParam1":@"value1"}
completion:^(id json, JSONModelError *err) {
//check err, process json ...
}];
将model转化为字典或者json格式的字符串
ProductModel* pm = [[ProductModel alloc] initWithString:jsonString error:nil];
pm.name = @"Changed Name";
//convert to dictionary
NSDictionary* dict = [pm toDictionary];
//convert to text
NSString* string = [pm toJSONString];
自定义数据的转换
@implementation JSONValueTransformer (CustomTransformer)
- (NSDate *)NSDateFromNSString:(NSString*)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:APIDateFormat];
return [formatter dateFromString:string];
}
- (NSString *)JSONObjectFromNSDate:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:APIDateFormat];
return [formatter stringFromDate:date];
}
@end
自定义处理指定的属性
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) float price;
@property (strong, nonatomic) NSLocale *locale;
@end
@implementation ProductModel
// Convert and assign the locale property
- (void)setLocaleWithNSString:(NSString*)string {
self.locale = [NSLocale localeWithLocaleIdentifier:string];
}
- (NSString *)JSONObjectForLocale {
return self.locale.localeIdentifier;
}
@end
自定义JSON校验
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) float price;
@property (strong, nonatomic) NSLocale *locale;
@property (strong, nonatomic) NSNumber <Ignore> *minNameLength;
@end
@implementation ProductModel
- (BOOL)validate:(NSError *__autoreleasing *)error {
BOOL valid = [super validate:error];
if (self.name.length < self.minNameLength.integerValue) {
*error = [NSError errorWithDomain:@"me.mycompany.com" code:1 userInfo:nil];
valid = NO;
}
return valid;
}
@end
- 错误处理
- 自定义数据校验
- 自动比较和相等判断
- 更多.
Misc
作者: Marin Todorov
参与者: Christian Hoffmann, Mark Joslin, Julien Vignali, Symvaro GmbH, BB9z.
任何人都可以 pull requests.
更新log : https://github.com/jsonmodel/jsonmodel/blob/master/CHANGELOG.md
Utility to generate JSONModel classes from JSON data: https://github.com/dofork/json2object
许可
This code is distributed under the terms and conditions of the MIT license.
参考指南
NB! 如果你解决了你发现的某个BUG, 请添加单元测试,这样以便我在合并之前复现这个BUG.
使用问题汇总
1、1.4.0版本的JSONKeyMapper
如果需要替换服务端返回来的key,需要按照下面的结构@{@"你的key":@"接口返回的key"},并且请使用initWithModelToJSONDictionary这个方法。
+ (JSONKeyMapper *)keyMapper {
return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:
@{
@"isChecked":@"ischecked",
@"tagId":@"tagid",
@"tagName":@"tagname",
@"tagValue":@"tagvalue"
}];
}
2、模型包含模型时的使用, 被包含的模型需要声明protocol
eg:KSAlreadyBuyListModel 包含一个属性KSAlreadyBuyModel, 我们需要将KSAlreadyBuyModel声明protocol,不然会解析失败。
@class StoryModel, AblumModel;
@protocol KSAlreadyBuyModel <NSObject>
@end
@interface KSAlreadyBuyModel : KSBaseModel
@property (nonatomic, strong) StoryModel *storyModel;
@property (nonatomic, strong) AblumModel *ablumModel;
@end
@protocol KSAlreadyBuyListModel <NSObject>
@end
@interface KSAlreadyBuyListModel : KSBaseModel
@property (nonatomic, copy) NSString *contentid;
@property (nonatomic, copy) NSString *contenttype;
@property (nonatomic, copy) NSString *iconurl;
@property (nonatomic, copy) NSString *orderno;
@property (nonatomic, copy) NSString *productid;
@property (nonatomic, copy) NSString *productname;
@property (nonatomic, copy) NSString *realityprice;
@property (nonatomic, strong) KSAlreadyBuyModel *param;
@end
网友评论
+(BOOL)propertyIsOptional:(NSString *)propertyName{
return YES;
}
NSString *nsPropertyName = @(propertyName);
if([[self class] propertyIsOptional:nsPropertyName]){
p.isOptional = YES;
}
会把所有的属性都做判断,其实也问题不大,我就这么用的
@property(nonatomic, retain) NSString<Optional> *name;
@end
用wcdb的话,加上<Optional>类似这样的关键词,会
[WCDB][ERROR]Code:2, Type:Abort, Msg:[(null)] should conform to WCTColumnCoding protocol, which is the class of [Message name]
难道wcdb和jsonmodel不能一起用吗?
最大的可能性就是服务端的类型和你声明的类型不匹配了
@property (nonatomic,assign)BOOL
BOOL和结构体 不能用Optional, 怎么解决
@implementation KSBaseModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
return YES;
}
- (id)valueForUndefinedKey:(NSString *)key {
return @"";
}
@end
"order_id": 104,
"total_price": 103.45,
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
}
兄弟。我遇到一个问题。这里面不是嵌套数组么?当products对应的数组返回为空的时候,会崩掉。设置忽略也没用。你遇到过么?
{
"code": "AAA",
"message": "BBB",
"result": null
}
但是正常情况下应该是 :
{"code":"AAA","message":"BBB","result":{"descrip":"CC","downloadUrl":"DD","forceUpdate":"EE","update":"FFF"}} 求指点。
在使用JSONModel的时候,如果服务器返回值为:“A”或“B”,我想要在Model类中直接转换为BOOL属性值如何转?(比如当服务器返回值为“A”时,转换为YES,否则转换为NO)
{
return [[JSONKeyMapper alloc] initWithDictionary:@{
@"order_id": @"id",
@"order_details.name": @"productName",
@"order_details.price.usd": @"price"
}];
}
这里边的key和value映射关系是不是写反了呢,应该是property作为key,json数据对应的key作为value吧
这样的话要依赖ModelB这个文件,如果不想依赖ModelB(因为要解耦),有什么好的方法吗?
另外这跟解耦没半毛的关系
这条太坑了,还得引入@protocol ProductModel,都没法写成
@property (strong, nonatomic) NSArray<ProductModel*>* products;
访问其数组内元素的时候,还是JSONModelArray,每次加入到其他数组都会报错
addObjectFromArray but argument is not array
+ (NSMutableArray *)arrayOfDictionariesFromModels:(NSArray *)array;
+ (NSMutableDictionary *)dictionaryOfDictionariesFromModels:(NSDictionary *)dictionary;
- (instancetype)initWithDictionary:(NSDictionary *)dict error:(NSError **)err;
传个err进去看看
第一个写你的model类里面声明的,第二个写服务端返回的字段。
eg:
@"orderId":@"id"
rderDetailDic{
od = {
cn = 0;
id = 1;
m = 18591925056;
n = drivername1;
s = 0;
sn = "\U7537";
};
ord = {
ct = 1473490442000;
did = 1;
id = 116;
p = 0;
pa = "";
pm = 3;
pmn = "\U7ebf\U4e0b\U652f\U4ed8";
rid = 727;
s = 0;
sn = "\U5df2\U521b\U5efa";
t = 1;
tn = "\U666e\U901a\U8ba2\U5355";
uid = 43;
};
ou = "<null>";
req = {
ct = 1473490440000;
i1 = "<null>";
i2 = "<null>";
id = 727;
n1 = "\U897f\U5b89\U4e9a\U6cf0\U6c7d\U8f66\U670d\U52a1\U6709\U9650\U516c\U53f8";
n2 = "jerry\U9020\U578b";
s = 3;
sn = "\U63a5\U5230\U4e58\U5ba2";
t = 0;
tn = "\U5b9e\U65f6";
x1 = 109;
x2 = 109;
y1 = 34;
y2 = 34;
};
}
请问,当遇到这种结构的json数据,使用jsonModel该怎样写数据模型?
{
"result" : [
{
"3" : {
"midpri" : "1152.00",
"buypri" : "1146.00",
"variety" : "美元账户铂金",
"maxpri" : "1153.00",
"minpri" : "1142.50",
"closeyes" : "1145.00",
"time" : "2016-08-01 10:05:00.0",
"todayopen" : "1147.00",
"quantpri" : "1.00",
"sellpri" : "1158.00"
},
"1" : {
"midpri" : "1350.45",
"buypri" : "1349.15",
"variety" : "美元账户黄金",
"maxpri" : "1351.65",
"minpri" : "1346.55",
"closeyes" : "1351.25",
"time" : "2016-08-01 10:05:00.0",
"todayopen" : "1350.00",
"quantpri" : "-2.10",
"sellpri" : "1351.75"
},
"4" : {
"midpri" : "706.50",
"buypri" : "700.50",
"variety" : "美元账户钯金",
"maxpri" : "710.50",
"minpri" : "704.50",
"closeyes" : "708.00",
"time" : "2016-08-01 10:05:00.0",
"todayopen" : "709.50",
"quantpri" : "-7.50",
"sellpri" : "712.50"
},
"2" : {
"midpri" : "20.56",
"buypri" : "20.49",
"variety" : "美元账户白银",
"maxpri" : "20.60",
"minpri" : "20.32",
"closeyes" : "20.35",
"time" : "2016-08-01 10:05:00.0",
"todayopen" : "20.35",
"quantpri" : "0.14",
"sellpri" : "20.63"
}
}
],
"resultcode" : "200",
"reason" : "SUCCESSED!",
"error_code" : 0
}
"2" : {
"midpri" : "20.56",
"buypri" : "20.49",
"variety" : "美元账户白银",
"maxpri" : "20.60",
"minpri" : "20.32",
"closeyes" : "20.35",
"time" : "2016-08-01 10:05:00.0",
"todayopen" : "20.35",
"quantpri" : "0.14",
"sellpri" : "20.63"
}这个2是多余的
```
{
"order_id": 104,
"total_price": 103.45,
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
}
```
{
"order_id": 104,
"total_price": 103.45,
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
}
@protocol ProductModel
@EnD
@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) float price;
@EnD
@Implementation ProductModel
@EnD
@interface OrderModel : JSONModel
@property (assign, nonatomic) int order_id;
@property (assign, nonatomic) float total_price;
@property (strong, nonatomic) NSArray<ProductModel>* products;
@EnD
@Implementation OrderModel
@EnD