阅读目录

 

因为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, 请持续关注后续版本。

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

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

    项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发 ...

  2. 如何在MyBatis中优雅的使用枚举

    问题 在编码过程中,经常会遇到用某个数值来表示某种状态.类型或者阶段的情况,比如有这样一个枚举:   public enum ComputerState { OPEN(10), //开启 CLOSE( ...

  3. 如何在 Swoole 中优雅的实现 MySQL 连接池

    如何在 Swoole 中优雅的实现 MySQL 连接池 一.为什么需要连接池 ? 数据库连接池指的是程序和数据库之间保持一定数量的连接不断开, 并且各个请求的连接可以相互复用, 减少重复连接数据库带来 ...

  4. 如何在swift中实现oc中的分类

    在oc中为了增强已有类的功能,我们经常使用分类.使用分类,我们可以在不破坏原有类的结构的前提下,对原有类进行模块化的扩展. 但是在swift中没有分类这种写法了.相对应的是swift中只有扩展(Ext ...

  5. iOS: 在Swift中优雅的实现Substring

    在Swift中,当我们想要截取某个字符串时,方法如下: let carNumber = "沪A12345" let startIndex = advance(userCar.car ...

  6. 如何在Vue中优雅的使用防抖节流

    1. 什么是防抖节流 防抖:防止重复点击触发事件 首先啥是抖? 抖就是一哆嗦!原本点一下,现在点了3下!不知道老铁脑子是不是很有画面感!哈哈哈哈哈哈 典型应用就是防止用户多次重复点击请求数据. 代码实 ...

  7. 如何在K8S中优雅的使用私有镜像库 (Docker版)

    前言 在企业落地 K8S 的过程中,私有镜像库 (专用镜像库) 必不可少,特别是在 Docker Hub 开始对免费用户限流之后, 越发的体现了搭建私有镜像库的重要性. 私有镜像库不但可以加速镜像的拉 ...

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

    最近在学习IOS开发,从一个简单的登录开始,逐步解决了一个网络访问.获取控件值等问题,遇到了信息加密的问题. 做为IOS的入门者,信息加密需要解决如下几个问题: 1.IOS的MD5加密有没有固定函数, ...

  9. 如何在php中优雅的地调用python程序

    1.准备工作   安装有python和php环境的电脑一台. 2.书写程序. php程序如下 我们也可以将exec('python test.py') 换成 system('python test.p ...

随机推荐

  1. -bash: ./job.sh: /bin/sh^M: bad interpreter: 没有那个文件或目录

    昨天在windows下用写字板写了个shell脚本,使用winscp上传到linux上运行的时候发现运行不了,提示-bash: ./job.sh: /bin/sh^M: bad interpreter ...

  2. POJ 1018 【枚举+剪枝】.cpp

    题意: 给出n个工厂的产品参数带宽b和价格p,在这n个工厂里分别选1件产品共n件,使B/P最小,其中B表示n件产品中最小的b值,P表示n件产品p值的和. 输入 iCase n 表示iCase个样例n个 ...

  3. Restlet+Fastjson 高速构建轻量级 Java RESTful Webservice

    自己入门Java时做过一个小型RESTful Web Service的项目,这里总结一下. 服务的数据交换格式主要採用JSON,服务为REST风格.连接採用Http协议,数据库使用MySQL,OR M ...

  4. 使用cacti监控服务器

    一.cacti安装 cacti需要lamp环境,因此需要首先编译安装lamp环境,安装完成后,下载cacti的zip包,解压到/www/htdocs目录下,创建cacti需要的数据库. 完成上述后,在 ...

  5. 《effective java》读书札记第三条用私有构造器或者枚举类型强化Singleton属性

    Singleton指只被实例化一次的类.一般用来搞那些创建很耗资源或者要求系统中只能有一个实例的类. 这个很经常使用.记得曾经实习面试的时候就有这个面试题. 一般採用的方法是将构造器私有化,然后提供一 ...

  6. 如何用C#使用java

    如何使用C#调用Java 今天需要使用C#调用Java的包,研究了一下,大体是以下几种解决方案: 把Java包转换为DLL或者EXE后注册为com组件,之后调用. 使用web service 比如:H ...

  7. 在mysql数据库中关于日期时间字段的处理

    在mysql数据库中关于日期时间字段的处理 在开发中,日期时间字段一般有如下几种设计 假设要获取2013-08-15日到2013-08-16日之间的记录 1. 直接使用日期时间类字段 相关sql语句如 ...

  8. Android开发之按键、触摸屏和手势输入专业压力測试方法

    按键输入.触摸屏输入和手势笔画输入等功能是Android开发的基本功能.其稳定性和健壮性对移动应用系统开发很重要.按键.触摸屏和手势输入专业压力測试方法能够使用Monkey,相应用程序进行压力測试,检 ...

  9. 共享库方案解决WAS中JAR包冲突

    实现步骤: 1.        准备共享库JAR包 commons-httpclient-3.1.jar httpclient-4.3.3.jar httpcore-4.3.2.jar httpmim ...

  10. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...