JSONModel解析数据成Model

下面讲一下JSONModel的使用方法。

@inteface MyModel : JSONModel

  1. 使用JSONModel时,不需要额外去检查所要的服务器属性是否有返回。JSONModel的initWithDictionary方法会自动去进行检查并处理。

  2. 有效性检查,如果指定的服务器返回的某个字段没有返回,而且又是必须的, 像下面这样写,则会抛出异常。

//this property is required
@property (strong, nonatomic) NSString* string;

因为默认这个值是必须的。

一般情况下,我们不想因为服务器的某个值没有返回就使程序崩溃, 我们会加关键字Optional.

//this one's optional
@property (strong, nonatomic) NSNumber<Optional>* number;
  1. 原子数据, 之前可能是如下面这样操作数据
if (jsonDict[@"name"])
labelName.text = jsonDict[@"name"];
else
[self showErrorMessageAndBailout];

这段代码会使得jsonDict[@”name”], 会被读取,然后进行有效性判断,最后再被使用。 换句话来说,这里使用了三次, 而如果某些情况下,使用一次就已经出错,但却无法阻止它接下来的连续出错。
而如果使用JSONModel的属性,则只会保证上面只使用一次,就可以进行有效性的判断以及使用。(其实上面也可以做到,只需要把这个值取出来,存下来接着使用却可,但是代码会稍显麻烦)

同时读取一批数据如下面代码:

简单模型如下:

SimpleModel* model = [[SimpleModel alloc] initWithString:@"...json here..." error:nil];


[objc] view plaincopy

复杂模型如下, 这里假设复杂模型包含了简单模型。主要是为了说明模型之前的包含情况下,照样可以进行解析。

[objc] view plaincopy

SuperComplicatedModel* model = [[SuperComplicatedModel alloc] initWithString:@"...json here..." error:nil];

模型的批处理,即一次可以处理一批模型。

[objc] view plaincopy

NSArray* models = [SuperComplicatedModel arrayOfObjectsFromDictionaries: jsonDatas error:nil];
  1. 数据转换, OC <-> JSON

注意下面这张图:这意味着JSON的数据格式只有中间的部分, string,number, array, object, 以及null

例如有如下 JSON数据:

{
   "first" : 1,
   "second": 35,
   "third" : 10034,
   "fourth": 10000
}

可以如下定义这个模型

[objc] view plaincopy
<span style="color:rgb(166,19,144)"></span>  
@interface NumbersModel:JSONModel

@property (assign,nonatomic) short first;
@property (assign,nonatomic) double second;
@property (strong,nonatomic) NSNumber* third;
@property (strong,nonatomic) NSString* fourth;

@end

注:JSON数据中, first为1,second为35, 但是它们却可以自动被转换成short, double类型。 对于10034, 以及10000会自动转换为NSNumber以及NSString。 这些都是JSONModel会自动进行的。 神奇吧!

  1. 内嵌的数据转换, 在JSONValueTransformer类中,有各种内嵌的转换支持。如下面
{
    "purchaseDate" : "2012-11-26T10:00:01+02:00",
    "blogURL" : "http://www.touch-code-magazine.com"
}

分别是一个 日期类型,以及一个URL类型。

@interface SmartModel: JSONModel

@property (strong, nonatomic) NSDate* purchaseDate;
@property (strong, nonatomic) NSURL* blogUrl;

@end

[objc] view plaincopy
<span style="color:rgb(166,19,144)"></span>  

用上面这个模型,不需要其它代码,即可以得到想要的转换 。
这个JSONValueTransformer类中有如下支持的转换

N

SMutableString <-> NSString
NSMutableArray <-> NSArray
NS(Mutable)Array <- JSONModelArray
NSMutableDictionary <-> NSDictionary
NSSet <-> NSArray
BOOL <-> number/string
string <-> number
string <-> url
string <-> time zone
string <-> date
number <-> date
  1. 自定义数据转换, 显然上面的内嵌转换有时不能满足我们的需要,所以我们需要如下的自定义转换。

你需要做的就是自定义一个JSONValueTransformer的类别文件,如下:

@interface JSONValueTransformer(UIColor)

-(UIColor*)UIColorFromNSString:(NSString*)string;
-(id)JSONObjectFromUIColor:(UIColor*)color;

@end

然后再进行实现即可。
注意上面的命名是采用:

-(YourPropertyClass*)YourPropertyClassFromJSONObjectClass:(JSONObjectClass*)name;

例如:

-(UIColor*)UIColorFromNSString:(NSString*)string;

而要把这个类型转换为JSON,则像这样即可:(注下面这个id,可以修改也可以不用修改成NSString,因为一定知道这是一个nsstirng. heqin:这里其实也可能会是其它类的,应该是根据特定情况来特定判断。)

-(id)JSONObjectFromYourPropertyClass:(YourPropertyClass*)color;

如下是另一个例子:

@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
  1. 层级嵌套。
{
    "idImage": 1,
    "name": "house.jpg",
    "copyright": {"author":"Marin Todorov", "year":2012}
}

可以先定义如下的模型

@interface CopyModel: JSONModel

@property (strong, nonatomic) NSString* author;
@property (assign, nonatomic) int year;

@end

然后再定义模型:

#import "CopyModel.h"
@interface ImageModel: JSONModel

@property (assign, nonatomic) int idImage;
@property (strong, nonatomic) NSString* name;
@property (strong, nonatomic) CopyModel* copyright;

@end

然后在你得到的ImageModel后, 就会发现其中的CopyModel也有数据了。
如果你想要一个数组的模型属性,如下即可。

@property (strong, nonatomic) NSArray<TweetModel>* tweets;
  1. JSONModel转换为Dictioanry, JSONString.

直接使用JSONModel的方法toDictioanry, 以及toJSONString即可。

  1. 保存model数据
NSDictionary* object = [NSDictionary dictionaryWithContentsOfFile:filePath];
data = [[MyDataModel alloc] initWithDictionary: object];
//保存操作
[[data toDictionary] writeToFile:filePath atomically:YES];
  1. Key mapping, 有时, 得到的数据不是在一个层级,如下:
{
    "order_id": 104,
    "order_details" : [
                       {
                           "name": "Product#1",
                           "price": {
                               "usd": 12.95
                           }
                       }
                       ]
}

其中的order_id与name就不是一个层级,但我们仍然想在一个model中得到它们的数据。 如下:

@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" // 这里就采用了KVC的方式来取值,它赋给price属性
                                                       }];
}

@end
  1. 全局Global key mapping. (使所有的模型都具备), 个人觉得这个并不是非常通用,因为如果真是需要所有模型都具备这个keyMapper的转换,则直接继承一个基类就行了。
[JSONModel setGlobalKeyMapper:[
                               [JSONKeyMapper alloc] initWithDictionary:@{
                                                                          @"item_id":@"ID",
                                                                          @"item.name": @"itemName"
                                                                          }]
 ];
  1. 自动把下划线方式的命名转为驼峰命名属性。还有类似的,如大写转为小写的方法:mapperFromUpperCaseToLowerCase
{
    "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
  1. 可选属性,建议尽量使用这种方式来避免异常。
{
    "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

通过上面的optional的方式, 我们可以给这个类添加一个isSuccess方法,该方法中判断name和uuid是否存在来决定是否从服务器成功取数据。 而不是把这两个属性设置为required,可以有效避免异常。

  1. Ignore属性, 会使得解析时会完全忽略它。 一般情况下,忽略的属性主要用在该值不从服务器获取,而是通过后面的代码进行设置。
{
    "id": "123",
    "name": null
}

模型为:

@interface ProductModel : JSONModel
@property (assign, nonatomic) int id;
@property (strong, nonatomic) NSString<Ignore>* customProperty;
@end

@implementation ProductModel
@end

可以用下面方法,使当前类的全部属性都为可选,官网上说尽量避免这样的使用, (个人觉得官网的意思是指,尽量避免用来面方法来指定所有的属性为可选,即使要全部属性为可选,也尽量是在每个属性那里标注为Optional)

@implementation ProductModel
+(BOOL)propertyIsOptional:(NSString*)propertyName
{
    return YES;
}
@end
  1. 延迟加载, 这种比较推荐,可以减少在网络读取时的性能消耗:关键字为: ConvertOnDemand
{
    "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, ConvertOnDemand>* products;
@end

@implementation OrderModel
@end

16. 使用JSONHttpClient进行请求。 

//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 ...

                               }];

好了, 所以的JSONModel的使用方法都已经在这里了, 综合了官网的使用方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值