如何在 Swift 中优雅地处理 JSON 【已翻译100%】

简介:

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

在Swift中使用JSON的问题

以Twitter API为例。使用Swift,从tweet中取得一个用户的“name”值应该非常简单。下面就是我们要处理的JSON:

[
  {
    ......
    "text": "just another test",
    ......
    "user": {
      "name": "OAuth Dancer",
      "favourites_count": 7,
      "entities": {
        "url": {
          "urls": [
            {
              "expanded_url": null,
              "url": "http://bit.ly/oauth-dancer",
              "indices": [
                0,
                26
              ],
              "display_url": null
            }
          ]
        }
      ......
    },
    "in_reply_to_screen_name": null,
  },
  ......]

在Swift中,你必须这样使用:

let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(dataFromTwitter, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statusesArray = jsonObject as? NSArray{
    if let aStatus = statusesArray[0] as? NSDictionary{
        if let user = aStatus["user"] as? NSDictionary{
            if let userName = user["name"] as? NSDictionary{
                //Finally We Got The Name

            }
        }
    }
}

或者,你可以用另外的一个方法,但这不易于阅读:

let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(dataFromTwitter, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let userName = (((jsonObject as? NSArray)?[0] as? NSDictionary)?["user"] as? NSDictionary)?["name"]{
  //What A disaster above
}

开始

下载在这儿下载SwiftyJSON,或者直接在GitHub克隆它:

git clone https://github.com/lingoer/SwiftyJSON.git

基础用法

SwiftyJSON的使用十分的简单:

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

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

let json = JSONValue(dataFromNetwork)

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

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

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

注意userName仍然是一个JSONValue。那怎样得到一个字符串呢?
你能用.string属性得到JSON数据表示的真正值。

let userNameString = userName.string!

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

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

注意每一种属性都是一个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.
}

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

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

枚举(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)

}
你可以使用一个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")

下标(Subscripts)

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

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

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

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

}

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

let userName = json[99999]["wrong_key"]

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

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

打印

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
        }
      ]
   }

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

let printableString = json.description

调试与错误处理

要是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
}

如果我们尝试使用错误的键值或索引来访问数据,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 
  }
}

后记

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

相关文章
|
JSON 数据格式 iOS开发
swift4.0 txt文件json取出转model
func chooseTxtContent() -> Void { guard let url = Bundle.main.url( forResource: "source/AllCountry/zh_Hans_CNCountry", withExt...
1019 0
|
JSON HandyJSON 数据格式
阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON
项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议。最常见的场景便是,客户端向服务端发起网络请求,服务端返回JSON文本,然后客户端解析这个JSON文本,再把对应数据展现到页面上。
1489 0
|
JSON 数据格式 缓存
swift语言IOS8开发战记24 解析Json
在IOS中使用NSURLConnection实现http通信,NSURLConnection提供了异步和同步两种通信方式,同步请求会造成进程阻塞,通常我们使用异步的方式,不管同步还是异步,建立通信的基本步骤都是一样的: 1,创建NSURL 2,创建Request对象 3,创建NSURLConnection连接 第3步结束后就建立了一个http连接。
866 0