用NSJSONSerialization讓JSON變服帖

之前的文章使用Ono讀取XML文件/簡書介紹了如何處理XML數(shù)據(jù),隨著Web時代的ajax的盛行,在App時代,另一個最常需要處理的的數(shù)據(jù)就是JSON數(shù)據(jù),尤其現(xiàn)在的Restful背景下API數(shù)據(jù)的傳遞,更有勝者直接就是JSON RPC。此時既要讀取解析JSON也要為數(shù)據(jù)結(jié)構(gòu)生成對應(yīng)的JSON數(shù)據(jù)。在以前,iOS/Mac平臺有多鐘JSON解決方案,如SBJSON、TouchJSON、YAJL、JSONKit,當(dāng)然還有C里面的cJSON/RapidJSON可以進行封裝,效率和正確率也是剛剛的。Apple自家也提供了一套解決方案:NSJSONSerialization,這個NSJSONSerialization比他們自家的XML解析工具NSXMLParser可好多了,他既有可人的接口,又提供了非凡的效率(有測評表明比SBJSON/JSONKit等強),并且是Apple系統(tǒng)提供的正規(guī)軍,因此首推這個方案。

NSJSONSerialization提供的接口非常簡單,甚至于官網(wǎng)的Manual只有少量的文字描述。

You use the NSJSONSerialization class to convert JSON to Foundation objects and convert Foundation objects to JSON

可見,NSJSONSerialization是可以直接將JSON數(shù)據(jù)轉(zhuǎn)換成Foundation中提供的對象如NSArray、NSDictionary、NSString、NSNumber等;也可以直接把這些Foundation的對象轉(zhuǎn)換成JSON數(shù)據(jù),這一看就是個超人性的接口。

但是這么好的接口也有些限制,他要求被解析的JSON數(shù)據(jù)必須是

  • 頂級對象需要是一個{}表示的字典或者[]表示的數(shù)組,因此也只能對NSArray/NSDictionary做序列化。(這點感覺基本都是這么用的)
  • 所有的節(jié)點數(shù)據(jù)必須要能被解析成 NSString, NSNumber, NSArray, NSDictionary 或者 NSNull.反之也只能對這些對象做序列化。
  • 字典的Key必須是NSString表達的類型。
  • 數(shù)字類型的數(shù)不能是NaN或者無限大。

總結(jié)來看其實只要我們:
在序列化的時候,只要是對NSArray或者NSDictionary對象序列化,并且其單元組成只能是 NSString, NSNumber(NaN/無限大不可以), NSArray, NSDictionary(key必須是NSString) 或者 NSNull即可。也可以通過

+ (BOOL)isValidJSONObject:(id)obj

這個類方法來判斷其是否可以被正確序列化。

1. 解析JSON數(shù)據(jù)到Foundation對象

NSJSONSerialization提供了兩個方法來解析JSON數(shù)據(jù),一個是從NSData里面取數(shù)據(jù),另一個是從NSInputStream 輸入流中取數(shù)據(jù),從而方便對File/Sokcet的操作。數(shù)據(jù)的格式必須是UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE中的一種,是否帶有BOM都可以。

+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;

+ (nullable id)JSONObjectWithStream:(NSInputStream *)stream options:(NSJSONReadingOptions)opt error:(NSError **)error;

兩個函數(shù)不同的地方就是第一個參數(shù),一個傳入的是NSData一個傳入的是NSInputStream.

options參數(shù)控制讀入的策略:

  • NSJSONReadingMutableContainers : 讀出來的對象放入到NSMutableArray或者NSMutableDictionary中,默認是放到NSArray/NSDictionary中。這個選項在我們讀取一段JSON然后進行追加或者刪除節(jié)點的時候,非常適合,修改下Array或者Dictionary成員,然后在序列化就可以了。
  • NSJSONReadingMutableLeaves: 讀出來的每個節(jié)點對象的String放入到NSMutableString中,這樣就為修改節(jié)點提供了可能,在讀入后修改節(jié)點再序列化回去的場景比較適用。
  • NSJSONReadingAllowFragments : 正常情況JSON的頂級節(jié)點要么是Array[]要么是Dictionary{}。如果JSON數(shù)據(jù)不是通過{}/[]表示的dictionary或者array的片段數(shù)據(jù),這用這個選項進行指定。

error參數(shù)是Cocoa API常用的出錯方式,傳入一個NSError **,如果出錯,通過這個值返回回來。
解析回來以后就可以按照NSArray或者NSDictionary的方式進行使用了,特別方便。比如:

{
    "id": 1,
    "name": "hanmeimei",
    "class": [
        "English",
        "Mathematics"
    ]
}

相當(dāng)于:

NSArray *myClass = @[@"English",@"Mathematics"];
NSDictionary *student = @{@"id":@1, @"name":@"hmeimei", @"class": myClass};

解析出來就是一個 student.

2. 將Foundation對象序列化到JSON中

與上面對應(yīng)的NSJSONSerialization也提供了兩個將對象序列化到JSON的接口,一個是序列化到NSData中,一個是序列化到NSOutputStream中,方便對File/Socket的操作,序列化的結(jié)果是UTF-8格式編碼數(shù)據(jù)。

+ (nullable NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;

+ (NSInteger)writeJSONObject:(id)obj toStream:(NSOutputStream *)stream options:(NSJSONWritingOptions)opt error:(NSError **)error;

兩個函數(shù)不同的地方就是第一個參數(shù),一個傳入的是NSData一個傳入的是NSOutputStream.

默認情況下,生成的JSON是盡量壓縮后的結(jié)果,去掉了不必要的空格,可讀性比較差。如果希望生成可讀性較好的格式,比如在調(diào)試的階段,可以使用NSJSONWritingPrettyPrinted 的option參數(shù)為輸出的格式加上必要空格,進行格式化。

同樣,如果序列化過程中出錯,通過error參數(shù)進行返回。在進行序列化的時候可以使用

+ (BOOL)isValidJSONObject:(id)obj;

判斷是否可以正常序列化。

比如上面的對student執(zhí)行序列化話,就可以得到上面的JSON數(shù)據(jù)。

3. 一個示例

最后通過一個示例程序看下基本的調(diào)用流程。

JSON文件為students.json:

[
    {
        "id": 1,
        "name": "hanmeimei",
        "class": [
            "English",
            "Mathematics"
        ]
    },
    {
        "id": 2,
        "name": "lilei",
        "class": [
            "English",
            "Mathematics"
        ]
    }
]

程序主要代碼:

NSInputStream *ifs = [[NSInputStream alloc] initWithFileAtPath:@"your_file_path/students.json"];
if (nil == ifs) {
    NSLog(@"ifs is nil");
    return -1;
}
[ifs open];
NSError *error = nil;
NSMutableArray *students = [NSJSONSerialization JSONObjectWithStream:ifs options:NSJSONReadingMutableContainers error:&error];
if (nil != error) {
    NSLog(@"Unparse JSON Error");
}
for (NSDictionary *student in students) {
    NSLog(@"student: %@", [student objectForKey:@"name"]);
    NSLog(@"    select class:");
    for (NSString *cls in [student objectForKey:@"class"]) {
        NSLog(@"        %@\\n", cls);
    }
}

// Parse To
NSDictionary *xiaowang =@{@"id":@3, @"name":@"xiaowang", @"class": @[@"none"]};
[students addObject:xiaowang];
error = nil;
NSData *jsonBuf  = [NSJSONSerialization dataWithJSONObject:students options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonStr = [[NSString alloc] initWithData:jsonBuf encoding:NSUTF8StringEncoding];
NSLog(@"JSON is %@", jsonStr);

輸出為:

student: hanmeimei
    select class:
         English
         Mathematics
student: lilei
    select class:
           English
           Mathematics
JSON is [
  {
"id" : 1,
"name" : "hanmeimei",
"class" : [
  "English",
  "Mathematics"
]
  },
  {
    "id" : 2,
    "name" : "lilei",
    "class" : [
      "English",
      "Mathematics"
    ]
  },
  {
    "id" : 3,
    "name" : "xiaowang",
    "class" : [
      "none"
    ]
  }
]

可以看到加空格的格式化效果還是比較明顯的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、iOS 4種JSON數(shù)據(jù)解析方法詳解 2013年09月10日? 綜合? 共 9124字? 字號小中大?評論關(guān)閉...
    lilinjianshu閱讀 2,287評論 0 2
  • JSON JSON和XML都是需要解析的 JSON是一種輕量級的數(shù)據(jù)格式,一般用于數(shù)據(jù)交互服務(wù)器返回給客戶端的數(shù)據(jù)...
    JonesCxy閱讀 2,016評論 2 10
  • NSURLSession基本使用 簡介 使用步驟使用NSURLSession會話對象創(chuàng)建Task,然后執(zhí)行Task...
    彼岸的黑色曼陀羅閱讀 1,118評論 0 3
  • iOS開發(fā)系列--網(wǎng)絡(luò)開發(fā) 概覽 大部分應(yīng)用程序都或多或少會牽扯到網(wǎng)絡(luò)開發(fā),例如說新浪微博、微信等,這些應(yīng)用本身可...
    lichengjin閱讀 4,046評論 2 7
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,445評論 4 61

友情鏈接更多精彩內(nèi)容