在Swift中优雅地处理JSON

因为Swift对于类型有非常严格的控制,它在处理JSON时是挺麻烦的,因为它天生就是隐式类型。SwiftyJSON是一个能帮助我们在Swift中使用JSON的开源类库。开始之前,让我们先看一下在Swift中处理JSON是多么痛苦。
首页 新闻资讯 行业资讯 在Swift中优雅地处理JSON

SwiftyJSON的使用十分的简单:

典型的NSURLSessionTask抓取Twitter的API将产生dataFromNetwork: NSData!:

你首先应该做的事情是初始化JSONValue:

复制

let json = JSONValue(dataFromNetwork)
  • 1.

JSONValue是一个枚举类型表示一个典型的JSON数据结构。

你能使用subscripts检索不同的值从原始的JSONValue中,像这样:

复制

let userName:JSONValue = json[0]["user"]["name"]
  • 1.

注意userName仍然是一个JSONValue。那怎样得到一个字符串呢?

你能用.string属性得到JSON数据表示的真正值。

复制

let userNameString = userName.string!
  • 1.

对每一种JSON类型, JSONValue都提供了一种属性检索它:

复制

var string: String? var number: NSNumber? var bool: Bool?  var array: Array<JSONValue>? var object: Dictionary<String, JSONValue>?
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

注意每一种属性都是一个Optional值。这是因为JSON数据能包含任何它定义的有效类型。

因此,建议的方式是用Optional绑定检索值:

复制

if let name = userName.string{     //This could avoid lots of crashes caused by the unexpected data types }   if let name = userName.number{     //As the value of the userName is Not a number. It won't execute.
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

.number属性产生一个NSNumber值,在Swift中这通常不是很有用。你能用.double或者.integer得到一个Double值或者一个Int值。

复制

if let intValue = numberValue.integer{     count += intValue }
  • 1.

  • 2.

  • 3.

枚举(Enumeration)

在Swift中JSONValue实际上是一个枚举:

复制

enum JSONValue {       case JNumber(NSNumber)     case JString(String)     case JBool(Bool)     case JNull     case JArray(Array<JSONValue>)     case JObject(Dictionary<String,JSONValue>)     case JInvalid(NSError)   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

你可以使用一个switch子句去更有效地获取值:

复制

let json = JSONValue(jsonObject) switch json["user_id"]{ case .JString(let stringValue):     let id = stringValue.toInt() case .JNumber(let numberValue):     let id = numberValue.integerValue default:     println("ooops!!! JSON Data is Unexpected or Broken")
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

下标(Subscripts)

注意,在JSON中一个数组结构被包装成intoArray<JSONVlaue>,它意味着数组里的每一个元素都是一个JSONValue。甚至你从JSONValue中取出一个数组,你仍然可以使用基本的属性去获取元素的值:

复制

if let array = json["key_of_array"].array{     if let string = array[0].string{         //The array[0] is still a JSONValue!     } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

对象也是一样。因此,推荐的方式是访问每一个数组和对象时使用JSONValue的下标。

复制

if let string = json["key_of_array"][0].string{   }
  • 1.

  • 2.

  • 3.

实际上,你可以用下标访问一个JSONValue,还不用担心运行时错误导致的崩溃:

复制

let userName = json[99999]["wrong_key"]
  • 1.

如果你使用推荐的方式去取数据,它是安全的:

复制

if let userName = json[99999]["wrong_key"]["name"].string{     //It's always safe }
  • 1.

  • 2.

  • 3.

打印

JSONValue遵守Printable协议.所以很容易在原始字符串中得到JSON数据:

复制

let json = JSONValue(dataFromNetwork) println(json) /*You can get a well printed human readable raw JSON string:       {         "url": {           "urls": [             {               "expanded_url": null,               "url": "http://bit.ly/oauth-dancer",               "indices": [                 0,                 26               ],               "display_url": null             }           ]        } */
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

如果你不想打印出来,你可以使用.description属性来得到上述字符串。

复制

let printableString = json.description
  • 1.

调试与错误处理

要是JSON数据出错或者我们错误地检索数据,那会怎么样呢?你可以使用if语句来测试:

复制

let json = JSONValue(dataFromNetworking)["some_key"]["some_wrong_key"]["wrong_name"] if json{   //JSONValue it self conforms to Protocol "LogicValue", with JSONValue.JInvalid stands for false and others stands true }
  • 1.

  • 2.

  • 3.

  • 4.

如果我们尝试使用错误的键值或索引来访问数据,description属性会高数你KeyPath在哪里出错了.

复制

let json = JSONValue(dataFromNetworking)["some_key"]["some_wrong_key"]["wrong_name"] if json{   } else {   println(json)   //> JSON Keypath Error: Incorrect Keypath "some_wrong_key/wrong_name"   //It always tells you where your key went wrong   switch json{   case .JInvalid(let error):     //An NSError containing detailed error information    } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

后记

 SwiftyJSON的开发将会发布在Github, 请持续关注后续版本。

本文链接:http://mobile.51cto.com/design-446157.htm

17    2014-07-22 09:01:53    Swift JSON