JSONModel的使用详解

JSONModel is a data model framework for iOS and OSX. It‘s written in Objective-C and helps you in several different ways.You can read more about its key features below:

  1. Rapidly write model code
  2. Validation of the model‘s input
  3. Atomic data
  4. Type casting between JSON and Obj-C
  5. Built-in data transformers
  6. Custom data transformers
  7. Model cascading
  8. Convert back & forth from/to JSON
  9. Persist model state in memory or file
  10. Create models straight from the Internet
  11. Automatic model compare methods

Features:

1. Rapidly write model code

If you have written iOS apps, which fetch and work with JSON from the web, you probably have written tons of this kind of code:

self.id = [jsonDict objectForKey:@"id"];
self.name = [jsonDict objectForKey:@"name"];
self.profileImageBig = [jsonDict objectForKey:@"profile_image_big"];
self.profileImageSmall = [jsonDict objectForKey:@"profile_image_small"];
self.profileImageSquare = [jsonDict objectForKey:@"profile_image_square"];
self.firstName = [jsonDict objectForKey:@"firstName"];
self.familyName = [jsonDict objectForKey:@"familyName"];
self.age = [jsonDict objectForKey:@"age"];

What sucks about this code is that you first need to declare all you properties in your interface file and then go ahead and write init method for your model that just reads the JSON through and copy all the values over to your propertis.

That‘s a lot of manual labor! But hey - it‘s the future now!

JSONModel removes the need to write initializer code to your models.

Just declare properties in your model with the same names as the keys in your JSON and voila! The heavy work is done automatically for you.

So, just declare your properties like usual in your interface file:

@interface MyModel: JSONModel
@property (strong, nonatomic) NSString* id;
@property (strong, nonatomic) NSString* name;
(etc...)
@end

JSONModel‘s inherited initWithDictionary: method will take care to match incoming JSON keys with your model‘s properties, and copy over the matching ones. No need of any code in your implementation file.

2. Validation of the model‘s input

Does *this* code look familiar to you?

self.profileURL = [jsonDict objectForKey:@"profileURL"];
//TODO: what to do if there‘s no url in the JSON? should we handle this somehow?
if (!self.profileURL) NSLog(@"something‘s broken with the json API");

When you write a model the traditional way, you also need to validate whether the keys your model need are found in the incoming JSON.

However, that‘s not always what‘s happening (partially due to the traditional way of handling errors in Cocoa, I wouldn‘t blame anybody for skipping on that).

Problem is - in the end you either write all the code to check whether the JSON keys exist, or you leave your app to free fall when there‘s a problem.

If your models inherit JSONModel, there‘s no need for extra code to check whether the required JSON structure is in place. JSONModel‘s initWithDictionary: method checks that automatically.

All properties you define in your model will be required. If they are not present in the input, you‘ll get an exception.

However you can also define some of the properties as not-required, and that‘s also very easy:

 
//this property is required
@property (strong, nonatomic) NSString* string;
 
//this one‘s optional
@property (strong, nonatomic) NSNumber<Optional>* number;

3. Atomic data

Having a good model guarantees you don‘t have half-baked User Interface or mysterious crashes. What am I talking about? Consider this code (that probably a colleague of yours wrote, it was not you for sure):

if (jsonDict[@"name"])
  labelName.text = jsonDict[@"name"];
else
  [self showErrorMessageAndBailout];
 
if (jsonDict[@"age"])
  labelAge.text = jsonDict[@"age"];
else
  [self showErrorMessageAndBailout];

Do you notice the problem? The code reads and validates and data, AND in the same time updates the user interface.

So, when an error occurs there‘s no way to rollback the already applied changes.

JSONModel does all data reading and validation atomically. You call one method, which either succeeds or fails and then you can use the data being sure it‘s valid and alright.

Here‘s how you make an instance of your data model when it contains just few strings and numbers:

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

And here‘s how you make an instance of model, which contains other models, and has JSON data converted to custom classes when read:

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

And here is how you read a list of 100 models, as each of them is the described above model:

NSArray* models = [SuperComplicatedModel arrayOfObjectsFromDictionaries: jsonDatas error:nil];

As you see - instantiation is always one-liner, which you can comfortably error handle.

4. Type casting between JSON and Obj-C

JSON is awesome but the problem with it is that both your backend (PHP, Ruby, C#, what have you) and your app (Objective-C) have rich types range, but JSON does NOT. To put things visually here‘s what happens when you consume a JSON feed from the web:
If you catch my drift - the JSON format is an incredible data type bottleneck in between your app and your server back end. While JSONModel lives on iOS it cannot do much about the part on the right side of JSON - the communication to your server.

What it can do is to help you cast the JSON data to Objective-C types!

Just define your properties‘ types as the types you‘d like to have and JSONModel will try to convert the incoming data to satisfy your needs.

Have a look at this JSON feed:

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

You have four keys and their values are numbers, therefore you get the same old NSNumber back when you parse the JSON yourself.

Not with JSONModel you don‘t! You just specify the types of your properties and JSONModel then converts the data for you, like so:

@interface NumbersModel: JSONModel
 
@property (assign, nonatomic) short first;
@property (assign, nonatomic) double second;
@property (strong, nonatomic) NSNumber* third;
@property (strong, nonatomic) NSString* fourth;
 
@end

Again - no implementation code needed for this to work!

5. Built-in data transformers

JSONModel comes with built-in value transformers, declared in a separate class called JSONValueTransformer. It handles basic value conversions between the most common class types, that you might use in a JSON feed.

The built-in transformers work behind the scene, so you‘d never even have to know they kick in and do the heavy lifting for you.

For example you might have this JSON:

{
  "purchaseDate" : "2012-11-26T10:00:01+02:00",
  "blogURL" : "http://www.touch-code-magazine.com"
}

This JSON includes a date in W3C format (widely used in JSON APIs), but it comes to your iOS app as a string, because JSON does not have a data type "date".

The second element in the JSON code is a URL; again it comes to you as plain string, since JSON does not have a URL data type.

To make use of the built-in transformers, just create your model as:

@interface SmartModel: JSONModel
 
@property (strong, nonatomic) NSDate* purchaseDate;
@property (strong, nonatomic) NSURL* blogUrl;
 
@end

JSONModel see that there‘s a mismatch between the incoming types and your model‘s properties types, and that when the transformers kick in and convert the values. In the end you just use your properties as normal. Smooth.

6. Custom data transformers

Of course not every value can be automatically converted to any other value. That‘s where you jump on board.

You can add transformers to JSONValueTransformer for your own project.

You need to make a new category on JSONValueTransformer and add two methods to this category. That‘s all. Like so:

@interface JSONValueTransformer(UIColor)
 
-(UIColor*)UIColorFromNSString:(NSString*)string;
-(id)JSONObjectFromUIColor:(UIColor*)color;
 
@end

This example adds transformer for a UIColor* property, which gets its value from a HEX encoded color coming in as a string. The first method you declare is named like so:

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

Therefore since the HEX color comes from JSON as an NSString, and your property is of type UIColor* your method name should be:

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

It makes sense? It‘s easy? Yes - I agree.

The second method you need for exporting your model to JSON (if you need to do that). It works in the same way, only that it doesn‘t imply what is the exported JSON object data type. It‘s up to you to decide.

Check the included JSONValueTransformer+UIColor.h/m files for a full example how to write custom transformers.

7. Model cascading

If you are working with a pretty complicated API, you will definitely need to have models, which contain other models.

Let me show you an example of an image, which beside simple properties, also contains a copyright, which is a model itself.

Here‘s the JSON you get:

{
  "idImage": 1,
  "name": "house.jpg",
  "copyright": {"author":"Marin Todorov", "year":2012}
}

It‘s pretty simple to define your models for this JSON. Just have first your copyright model defined:

@interface CopyModel: JSONModel
 
@property (strong, nonatomic) NSString* author;
@property (assign, nonatomic) int year;
 
@end

And then define your Image model, which contains the copyright model, like so:

#import "CopyModel.h"
@interface ImageModel: JSONModel
 
@property (assign, nonatomic) int idImage;
@property (strong, nonatomic) NSString* name;
@property (strong, nonatomic) CopyModel* copyright;
 
@end

That‘s it. When you initialize an instance of the ImageModel, it will see that one of the properties is a JSONModel itself, and will parse properly the JSON input. Boom!

How about when you don‘t have a single model as a property, but a list of models for example?

Well JSON lists come through as NSArray objects, you just have to also specify which model you expect in the list:

 
@property (strong, nonatomic) NSArray<TweetModel>* tweets;

And for that to work you also need to add a protocol definition to your model interface file, and the protocol name should match your model name. So for a model called TweetModel (as in the example above), add in TweetModel.h:

 
@protocol TweetModel @end

That‘s it. Now your top model can cascade inside the JSON structure and read through multilevel structures.

8. Convert back & forth from/to JSON

A great model converts back to the format it was loaded from. Therefore JSONModel features a default toDictionary method, and another one calledtoJSONString.

You can then easily turn your model to a JSON compliant object at any time by calling toDictionary on your model‘s instance.

Or you can just get the text representation of your current model data by calling toJSONString.

Pretty handy if you need to send the modified model back over the network to your server!

9. Persist model data in memory or file

And finally you can use JSONModel as an easy way to store files on your device‘s disc. Since data typing and converting to JSON compliant types is already handled for you, you just need to call a single method to save to the disc.

Loading model form the disc:

//load from file
NSDictionary* object = [NSDictionary dictionaryWithContentsOfFile:filePath];
 
//initialize model with data
data = [[MyDataModel alloc] initWithDictionary: object];

And saving it back to the disc:

//save to disc
[[data toDictionary] writeToFile:filePath atomically:YES];

10. Create models straight from the Internet

Docs coming in soon...

11. Automatic model compare methods

Docs coming in soon...

时间: 2025-01-14 01:57:43

JSONModel的使用详解的相关文章

iOS疯狂详解之开源库

youtube下载神器:https://github.com/rg3/youtube-dl vim插件:https://github.com/Valloric/YouCompleteMe vim插件配置:https://github.com/spf13/spf13-vim ----------------Mac完整项目---------- 电台:https://github.com/myoula/sostart ----------------iOS完整项目---------------- 1,

Spring事务管理(详解+实例)

写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都

转载:DenseNet算法详解

原文连接:http://blog.csdn.net/u014380165/article/details/75142664 参考连接:http://blog.csdn.net/u012938704/article/details/53468483 本文这里仅当学习笔记使用,具体细节建议前往原文细度. 论文:Densely Connected Convolutional Networks 论文链接:https://arxiv.org/pdf/1608.06993.pdf 代码的github链接:h

MariaDB(MySQL)创建、删除、选择及数据类型使用详解

一.MariaDB简介(MySQL简介略过) MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品.在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB. MariaDB由MySQL的创始人Michael Widenius(英语:Michael Widenius)主导开发,他早前曾以10亿美元的价格,将自己创建的公司MySQL A

HttpServletResponse和HttpServletRequest详解

HttpServletResponse,HttpServletRequest详解 1.相关的接口 HttpServletRequest HttpServletRequest接口最常用的方法就是获得请求中的参数,这些参数一般是客户端表单中的数据.同时,HttpServletRequest接口可以获取由客户端传送的名称,也可以获取产生请求并且接收请求的服务器端主机名及IP地址,还可以获取客户端正在使用的通信协议等信息.下表是接口HttpServletRequest的常用方法. 说明:HttpServ

POSIX 线程详解(经典必看)

总共三部分: 第一部分:POSIX 线程详解                                   Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  2000 年 7 月 01 日 第二部分:通用线程:POSIX 线程详解,第 2部分       Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  20

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

netstat状态详解

一.生产服务器netstat tcp连接状态................................................................................ 2 1.1生产服务器某个业务LVS负载均衡上连接状态数量............................................... 2 1.2生产服务器某个业务web上连接状态数量...............................................

详解go语言的array和slice 【二】

上一篇  详解go语言的array和slice [一]已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多.上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变.这一篇里我会讲解到如何避免这些问题,以及迭代.和做为方法参数方面的知识点. slice的长度和容量设置为同一个值 如果在创建新的slice时我们把