無線客戶端框架設(shè)計(jì)(5.1):將JSON映射為實(shí)體對象(iOS)
iOS開發(fā)人員已經(jīng)習(xí)慣于將JSON轉(zhuǎn)換為字典或者數(shù)組來進(jìn)行操作了,接下來我要做的事情,可能匪夷所思,但是,對WP和Android開發(fā)人員而言,他們更傾向于將JSON轉(zhuǎn)換為實(shí)體對象進(jìn)行操作。
我所設(shè)計(jì)的客戶端框架,三個(gè)平臺之間互相取長補(bǔ)短,保持統(tǒng)一的思想,而其中最重要的一環(huán)就是,面向?qū)ο蟮木幊谭绞健?/p>
書接上文,我在異步調(diào)用完MobileAPI并成功獲取到JSON后,僅僅將其轉(zhuǎn)換為jsonValue,如下所示:
后續(xù)要做的事情,就是把jsonValue轉(zhuǎn)換為實(shí)體對象了。
首先,要說一下JSON的格式。
MobileAPI返回的JSON字符串有幾種格式:
1)單一實(shí)體:
a)簡單屬性:
- {
- "userName": "baobao",
- "userAge": 18
- }
b)屬性中有復(fù)合屬性,且該復(fù)合屬性是另一個(gè)自定義實(shí)體:
- {
- "UserId": 1,
- "UserInfo": {
- "userName": "baobao",
- "userAge": 18
- }
- }
c)屬性中有復(fù)合屬性,且該復(fù)合屬性是一個(gè)數(shù)組:
- {
- "Career": "IT",
- "Users": [
- {
- "userName": "Bill.Gates",
- "userAge": 60
- },
- {
- "userName": "baobao",
- "userAge": 18
- }
- ]
- }
2)數(shù)組
a)規(guī)范的寫法:
- {
- "Users": [
- {
- "userName": "Bill.Gates",
- "userAge": 60
- }
- {
- "userName": "baobao",
- "userAge": 18
- }
- ]
- }
b)不規(guī)范的寫法:
- [
- {
- "userName": "Bill.Gates",
- "userAge": 60
- },
- {
- "userName": "baobao",
- "userAge": 18
- }
- ]
對以上格式進(jìn)行歸納,我們發(fā)現(xiàn),只需要指定好:
1)整個(gè)JSON字符串是規(guī)范的(這時(shí)是一個(gè)字典),還是不規(guī)范的(這時(shí)是一個(gè)數(shù)組)
2)對于規(guī)范的JSON字符串,每個(gè)JSON字段映射為實(shí)體的哪個(gè)字段,就是說,from是什么,to是什么?
3)實(shí)體字段的數(shù)據(jù)類型。對于JSON而言,簡單類型,只有NSString和NSNumber兩種(日期按字符串對待,布爾值按整數(shù)0和1對待)。復(fù)合類型,有2種:要么是一個(gè)自定義實(shí)體(這時(shí)是一個(gè)字典),要么是一個(gè)數(shù)組。
基于此,我們創(chuàng)建統(tǒng)一格式的實(shí)體格式如下:
//以下為UserEntity.h文件:
- #import <Foundation/Foundation.h>
- @class ObjectMapping;
- @interface UserEntity : NSObject
- {
- NSString *name;
- NSNumber *age;
- }
- @property (nonatomic,retain) NSString *name;
- @property (nonatomic,retain) NSNumber *age;
- - (ObjectMapping *)objectMapping;
- @end
- //以下為UserEntity.m文件:
- #import "UserEntity.h"
- #import "ObjectMapping.h"
- @implementation UserEntity
- @synthesize name;
- @synthesize age;
- - (ObjectMapping *)objectMapping {
- ObjectMapping *mapping = [ObjectMapping mappingForClass:[UserEntity class]];
- [mapping converEntityFromJsonToEntity:@"userName" to:@"name" withClass: @"NSString"];
- [mapping converEntityFromJsonToEntity:@"userAge" to:@"age" withClass: @"NSNumber"];
- return mapping;
- }
- - (void)dealloc {
- [name release];
- [age release];
- [super dealloc];
- }
- @end
在格式統(tǒng)一的情況下,我們來討論在MyApp中是如何使用的,參見APageViewController.m文件,我們繼續(xù)改造上一節(jié)沒有完成的requestFinished方法:
通過ObjectMappingLoader的loadObjectWithClassName方法,我們將jsonValue轉(zhuǎn)換為實(shí)體 result,然后再一次將result強(qiáng)制轉(zhuǎn)換為WeatherWrapEntity類型的實(shí)體。接下來我們就可以使用 weatherWrapEntity實(shí)體中的任何屬性了,都是JSON里面返回的數(shù)據(jù)。
使用起來非常簡單,但這一切都是MyLib類庫下ObjectMapping目錄中的3個(gè)類來實(shí)現(xiàn)的:
原理比較簡單,使用到了迭代算法,把JSON格式的字符串先轉(zhuǎn)換為字典,然后再迭代之,轉(zhuǎn)換為實(shí)體。
本節(jié)源碼如下: YoungHeart-Chapter-05-1.zip
另外,對各種情況的模擬,參見MyApp下的MyAppTest目錄,這是一個(gè)單元測試,相應(yīng)的Target為MyAppTests,每次修改 MyLib的時(shí)候不是要把libMyLib.a重新引入到MyApp項(xiàng)目的MyApp這個(gè)Target中嘛,請同時(shí)將其也引入到MyAppTests這個(gè) Target中。