• 如何在 Swift 中优雅地处理 JSON


    阅读目录

     

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

    在Swift中使用JSON的问题

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    [
      {
        ......
        "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中,你必须这样使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
     
                }
            }
        }
    }

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

    1
    2
    3
    4
    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克隆它:

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

    基础用法

    SwiftyJSON的使用十分的简单:

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

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

    1
    let json = JSONValue(dataFromNetwork)

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

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

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

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

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

    1
    let userNameString = userName.string!

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

    1
    2
    3
    4
    5
    var string: String?
    var number: NSNumber?
    var bool: Bool? 
    var array: Array<JSONValue>?
    var object: Dictionary<String, JSONValue>?

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

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

    1
    2
    3
    4
    5
    6
    7
    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值。 

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

    枚举(Enumeration)

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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子句去更有效地获取值:

    1
    2
    3
    4
    5
    6
    7
    8
    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<JSONVlaue>,它意味着数组里的每一个元素都是一个JSONValue。甚至你从JSONValue中取出一个数组,你仍然可以使用基本的属性去获取元素的值:

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

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

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

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

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

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

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

    打印

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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属性来得到上述字符串。

    1
    let printableString = json.description

    调试与错误处理

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

    1
    2
    3
    4
    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在哪里出错了.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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, 请持续关注后续版本。

  • 相关阅读:
    EChart处理三维数据做图表、多维legend图例处理
    详解Vuex常见问题、深入理解Vuex
    解决vuex在页面刷新后数据丢失的问题
    vue-router路由元信息详解
    修改Nginx与Apache配置参数解决http状态码:413上传文件大小限制问题
    ab.exe使用
    项目经验
    消息队列系列(一):.Net平台下的消息队列介绍
    【转】谈基于SOA的应用系统设计和开发
    2015年12周(2015-03-16~2015-03-22)
  • 原文地址:https://www.cnblogs.com/simadi/p/4392454.html
Copyright © 2020-2023  润新知