如何在 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, 请持续关注后续版本。

本文地址:http://www.oschina.net/translate/swiftyjson-how-to-handle-json-in-swift

原文地址:http://www.binpress.com/tutorial/swiftyjson-how-to-handle-json-in-swift/111

时间: 2024-10-06 10:41:12

如何在 Swift 中优雅地处理 JSON的相关文章

阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发起网络请求,服务端返回JSON文本,然后客户端解析这个JSON文本,再把对应数据展现到页面上. 但在编程的时候,处理JSON是一件麻烦事.在不引入任何轮子的情况下,我们通常需要先把JSON转为Dictionary,然后还要记住每个数据对应的Key,用这个Key在Dictionary中取出对应的Val

如何在vi中优雅地使用ex

记得刚开始用vi的时候,只会用:wq或者:q来退出,后来又学会了ZZ,今天上班路上没事做,又把 Learning the Vi & Vim 的 Introducing the ex Editor 过了一遍,又发现了一个退出命令-:x,其实很早以前这些内容都看过,但是由于使用惯性,渐渐地会把一些平时不太用到的命令给遗忘了,其实一个防止遗忘的好办法就是认真总结一下,方便以后查阅. 其实当我们在命令模式下按下冒号后,就已经进入ex编辑模式了,也就是说退出时使用的命令wq q x其实都是ex的命令.vi

如何在swift中使用cocoapods导入的第三方oc库

假如你来到这里,说明你已经开始着手使用swift这门新语言了. 就像Java有Maven一样,Objective-C也有自己的依赖管理工具cocoapods. 但是由于swift才出来不久,目前很多cocoapods管理的第三方库依然是由Objective-C编写的. 为了能够在swift中使用这些类库,需要在Xcode中进行一些配置. 假设你的项目是基于cocoapods的,并且是通过XX.xcworkspace打开的.(Xcode6以上) 为了进行演示,假设导入的第三方库是MBProgres

如何在Swift中创建自定义控件

更新通知:这篇引导教程由Mikael Konutgan使用iOS 8和Swift语言重新制作,在Xcode6和7上测试通过.原始教程是由Colin Eberhardt团队制作的. 用户界面控件是许多应用的重要组成部分.使用这些控件,可以让用户查看应用的内容或与他们的应用进行交互.苹果提供了一个控件集,像UITextField, UIButton 和 UISwitch.灵活使用这些工具箱中已经存在的控件,可以让你创建各种各样的用户界面. 但是,有的时候你可能需要做一些与众不同的事情:库中的控件已经

iOS: 在Swift中优雅的实现Substring

在Swift中,当我们想要截取某个字符串时,方法如下: let carNumber = "沪A12345" let startIndex = advance(userCar.carPlateNumber.startIndex, 0) let endIndex = advance(startIndex, 1) let range = startIndex..<endIndex println(carNumber[range]) // 输出沪 呃,好怀念substring方法啊,那我

如何在Swift中使用NSError

步骤一:声明NSError变量.一定要加"?",不加或者加"!"都不行.因为使用了optional,所以要用var而不用let. var error: NSError? 步骤二:使用的时候在变量前加上"&". NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers, error: &error) 之前遇到的坑是NSError使用的是&quo

如何在Word中优雅的插入Latex线性公式

写论文的小伙伴应该都有过这样的感受!普通二次公式的手动插入如果说是尚可忍受的话,那么做人工智能学习和物理研究的小伙伴在插入二项式定理和傅立叶公式的时候,如果是手动输入....我想不必多说了,下面我就来介绍下,如果配合Mathpix在word中优雅的输入基于Latex的线性公式. LaTeX 作为一款「史诗级」文章排版编译器,一直都有着优秀.高效的排版体验和简洁.一致的排版效果.但是 LaTeX 相对复杂的语法使用,让我们很多时候都需要花费大量时间在查阅 LaTeX 的参考文档上,才能得到我们想要

IOS开发问题录:如何在Swift中引入Head文件?

最近在学习IOS开发,从一个简单的登录开始,逐步解决了一个网络访问.获取控件值等问题,遇到了信息加密的问题. 做为IOS的入门者,信息加密需要解决如下几个问题: 1.IOS的MD5加密有没有固定函数,怎么使用这个函数.. 经过查资料,在Object-C中有内置的函数 2.如何引入Object-C的函数 首先添加头文件,在xode 7 项目上右键 -new File->IOS->Source->HeadFile->下一步设置命名,可以任意命名,在head.h中加入如下代码: #imp

如何在Vuejs中优雅使用Javascript各种插件

在日常开发中,为了敏捷开发或者更快满足业务需求,不得不使使用js第三方库或者插件. 如何在Vue项目中引入javascript第三方库 全局变量 将 JavaScript 第三方库 添加到项目中,最简单的办法是通过将其附加到 window 对象上,以使其成为全局变量. 如何引入: window._ = require('lodash'); 如何使用: export default { created() { console.log(_.isEmpty() ? 'Lodash everywhere