【译】SwiftyJSON 中文文档翻译

前言

最近正在编写 iOS APP 的后台接口,调试的时候要解析JSON数据,所以就来学习使用 SwiftyJSON 这个第三方库,但网上搜的资料感觉写的都不怎么样,最后就只能硬着头皮看官方的文档了,尝试着翻译,借此机会学习并且提高一下自己的 English 水平吧。Let's GO. (PS: 虽然官网也有中文翻译,但是好像不是很全。。。。。😆).如果有翻译错误❎,请见谅也请指出,谢谢!

SwiftyJSON 使得在 Swift 下处理 JSON 数据变得非常容易。

  1. [为什么在 Swift 下处理 JSON 数据的方式不是很好](#为什么在 Swift 下处理 JSON 数据的方式不是很好)
  2. 需求
  3. 整合
  4. 用法
  5. [和 Alamofire 一起使用](#和 Alamofire 一起使用)

为什么在 Swift 下处理 JSON 数据的方式不是很好

Swift 是一种严格的类型安全的语言。尽管明确的类型有利于我们减少错误,但是当我们在处理 JSON 和 其他隐式数据类型的时候就变得很痛苦。

拿 Twitter API 举个栗子。我将在 Swift 的下取回一个用户的 “名字”(根据 Twitter 的 API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline)。

代码是这样子的:

if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
    let user = statusesArray[0]["user"] as? [String: Any],
    let username = user["name"] as? String {
    // Finally we got the username
}

这样不是很好。

即使我们使用可选绑定,看起来也是一团糟:

if let JSONObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
    let username = (JSONObject[0]["user"] as? [String: Any])?["name"] as? String {
        // There's our username
}

不可读的、一团糟。但是有些东西应该是简单的。

用 SwiftyJSON 你只需这么做:

let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string {
  //now you got your value
}

并且你也不用担心可选类型拆包。这些都是自动帮你完成。

let json = JSON(data: dataFromNetworking)
if let userName = json[999999]["wrong_key"]["wrong_name"].string {
  //calm down, take it easy. the ".string" property still produces the current Optional String type with safety
} else {
  //print the error
  print(json[999999]["wrong_ket"]["wrong_name"])
}

需求

  • iOS 8.0+ | macOS 10.10+|watch 2.0+

  • Xcode 8

整合

CocoaPods(iOS 8+, OS X 10.9+)

你可以使用 CocoaPods 来 安装 SwiftyJSON ,只要把一下的添加到 Podfile :

platform :iOS, '8.0'
use_frameworks!

target 'YourAPPName' do
pod 'SwiftyJSON'
end

注意这需要 CocoaPods 版本 36,并且你的 iOS 开发版本至少是 8.0:

Carthage(iOS 8+,OS X 10.9+)

你可以通过使用 Cathage 来安装 SwiftyJSON ,只需把一下的添加到 Cartfile:

github "SwiftyJOSN/SwiftyJSON"
Swift Package Manager

你可以使用 The Swift Package Manager 来安装 SwiftyJSON ,只需添加合适的描述到你的 Package.swift 文件:

import PackageDescription

let package = Package(
    name: "YOUR_PROJECT_NAME",
    targets: [],
    dependencies: [
            .Package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", versions: Version(1, 0, 0)..<Version(3, .max, .max)),
    ]
)

注意, Swift Package Manager 任然处于早期设计和开发阶段,更多信息请查看 GitHub Page

手动添加(iOS7+,OS X 10.9+)

为了在你的项目中使用这个库你通常需要:

  1. 对于单个项目,只需将 SwiftyJSON.swift 拖进你的项目
  2. 对于工作组,包含整个 SwiftyJSON.xcodeproj

用法

初始化
import SwiftyJSON   
let json = JSON(data: dataFromNetworking)
let json = JSON(jsonobject)
if let dataFromString = jsonString.data(using: .utf8, allowLossyConversion: false) {
  let json = JSON(data: dataFromString)
}
下标
//从 JSON数组 中获取一个 double
let name = json[0].double
//从一个 JSON数组 里获取一个 字符串数组
let arrayNames = json["users"].arrayValue.map({$0["name"].stringValue})
//从一个 JSON字典 中获取一个 string
let name = json["name"].stringValue
//通过元素的路径来获取 string
let path: [JSONSubscriptType] = [1, "list", 2, "name"]
let name = json[path].string
//同样的
let name = json[1]["list"][2]["name"].string
//或者
let name = json[1, "list", 2, "name"].string
//条件苛刻的情况
let name = json[].string
//普通的方法
let keys: [SubscriptType] = [1, "list", 2, "name"]
let name = json[keys].string
循环
//如果 JSON 是字典
for (key, subJson):(String, JSON) in json {
  //做你想做的事情
}

即使 JSON 是数组,第一个元素也总是字符串。

//如果 JSON是数组
//index 是0到JSON数量的一个字符串值
for (index, subJson):(String, JSON) in json {
  //做你想做的事情
}
错误

使用下标来获取或设置字典或数组里的一个值

如果 JSON 是:

  • 一个数组,应用可能奔溃由于数组越界。
  • 一个字典,它将返回 nil 并且没有原因。
  • 不是字典或者数组,应用可能因为“不认识选择器”而奔溃。

这些在 SwiftyJSON 中都不会发生。

let json = JSON(["name", "age"])
if let name = json[999].string {
  //做你想做的事情
} else {
  print(json[999].error)//"Array[999] 已经越界了"
}
let json = JSON(["name":"Jack", "age": 25])
if let name = json["address"].string {
  //做你想做的事情
} else {
  print(json["address"].error)//"Dictionary["address"]并不存在"
}
let json = JSON(12345)
if let age = json[0].string {
  //做你想做的事情
} else {
  print(json[0]) // "Array[0] 失败,这不是一个数组"
  print(json[0].error) // "Array[0] 失败, 这不是一个数组"
}

if let name = json["name"].string {
  //做你想做的事情
} else {
  print(json["name"]) //"Dictionary[\"name"] 失败, 这不是一个字典"
  print(json["name"].error) //"Dictionary[\"name"] 失败,这不是一个字典"
}
Optional getter
//数字
if let id = json["user"]["favourites_count"].number {
  //做你想做的事情
} else {
  //打印错误
  print(json["user"]["favourites_count"].error)
}
//字符串
if let id = json["user"]["name"].string {
  //做你想做的事情
} else {
  //打印错误
  print(json["user"]["name"])
}
//bool
if let id = json["user"]["is_translator"].bool {
  //做你想做的事情
} else {
  //打印错误
  print(json["user"]["is_translator"])
}
//整型
if let id = json["user"]["id"].int {
  //做你想做的事情
} else {
  //打印错误
  print(json["user"]["id"])
}
...
Non-optional getter

非可选 getter 名为 xxxValue

//如果不是数字或者空,返回 0
let id : Int = json["id"].intValue
//如果不是字符串或者空,返回 ""
let name: String = json["name"].stringValue
//如果不是数组或者空,返回 []
let list: Array<JSON> = json["list"].arrayValue
 //如果不是字典或者空,返回 [:]
 let user: Dictionary<String, JSON> = json["user"].dictionaryValue
setter
json["name"] = JSON("new-name")
json[0] = JSON(1)
json["id"].int = 1234567890
json["coordinate"].double = 9766.766
json["name"].string = "jack"
json.arrayObject = [1, 2, 3, 4]
json.dictionaryObject = ["name" : "Jack", "age" : 25]
元对象
let jsonObject: Any = json.object
if let jsonObject: Any = json.rawValue
//把 JSON 转化为字符串元
if let data = json.rawData() {
  //做你想做的事情
}
//把 字符串元转化为 JSON
if let string = json.rawString() {
  //做你想做的事情
}
存在性
//用来显示 JSON 中是否有指定的值
if json["name"].exist()
文字转换

更多关于文字转换的信息:Swift Literal Convertibles

//字符串转换
let json: JSON = "I'm a json"
//整型转换
let json: JSON = 1234
//Bool型转换
let json: JSON = true
//单精度浮点数转换
let json: JSON = 2.8756
//字典转换
let json: JSON = ["I" : "am", "a" : "json"]
//数组转换
let json: JSON = ["I", "am", "a", "json"]
//空转换
let json: JSON = nil
//带有下标的数组
var json: JSON = [1, 2, 3]
json[0] = 100
json[1] = 200
json[3] = 300
json[999] = 300 //别担心, 什么都不会发生
//带有下标的字典
var json: JSON = ["name" : "Jack", "age" : 25, "list" : ["a", "b", "c", ["what" : "this"]]]
json["list"][3]["what"] = "that"
json["list", 3, "what"] = "that"
let path: [JSONSubscriptType] = ["list", 3, "what"]
jaon[path] = "that"
//带有其他的 JSON 对象
let user: JSON = ["username" : "Strve", "password" : "supersecurepassword"]
let auth: JSON = [
  "user": user.object //使用 user.object 替代 user
  "apikey": "supersecuretapitoken"
]
合并

把一个 JSON 与另外一个 JSON 合并是可能的。合并两个 JSON 会把原始 JSON 中不存在的只出现在另外一个 JSON 中的数据添加进来。

如果两个 JSON 包含了的值有相同的键,通常情况下会重写原JSON的值,但是有两种情况下会有特别的处理:

  • 在两个值都是JSON.Type.array 的情况下,值形成在另一个JSON中的数组,附加到原始JSON的数组值。
  • 在两个值都是 JSON.Type.dictionary 的情况下,两个JSON值都以合并封装JSON的相同方式合并。

在JSON中的两个字段具有不同类型的情况下,值将始终被覆盖。

有两种不同的方式合并: merge 修改原始的 JSON ,而合并在副本上以非破坏性方式工作。

let original: JSON = [
    "first_name": "John",
    "age": 20,
    "skills": ["Coding", "Reading"],
    "address": [
        "street": "Front St",
        "zip": "12345",
    ]
]

let update: JSON = [
    "last_name": "Doe",
    "age": 21,
    "skills": ["Writing"],
    "address": [
        "zip": "12342",
        "city": "New York City"
    ]
]

let updated = original.merge(with: update)
// [
//     "first_name": "John",
//     "last_name": "Doe",
//     "age": 21,
//     "skills": ["Coding", "Reading", "Writing"],
//     "address": [
//         "street": "Front St",
//         "zip": "12342",
//         "city": "New York City"
//     ]
// ]

文字表示

有两种可选可以用:

  • 使用 Swift 默认的
  • 使用一个自定义的,可以很好地处理可选项,并将 nil 表示为 “null” :
let dict = ["1":2, "2":"two", "3": nil] as [String: Any?]
let json = JSON(dict)
let representation = json.rawString(options: [.castNilToNSNull: true])
// representation is "{\"1\":2,\"2\":\"two\",\"3\":null}", which represents {"1":2,"2":"two","3":null}

和 Alamofire 一起使用

SWiftyJSON 很好地包装了 Alamofire JSON 相应的结果:

Alamofire.request(url, mothod: .get).validate().responseJSON {
  response in
  switch response.result {
    case .success(let value):
        let json = JSON(value)
        print("JSON:\(json)")
    case .failure(let error):
        print(error)
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,983评论 4 60
  • 曾经妈妈让我在海边画个圆, 告诉我那就是世界, 而我悄悄端起着一捧砂砾, 告诉妈妈:世界是不是就在我的手中了? 妈...
    墨小凝阅读 235评论 0 2
  • 近日,大幂幂又上了热搜,而这次上热搜的原因不是因为和老公刘恺威的事情,而是由于发际线太高。 自从杨幂主演的新剧《三...
    整了么娱乐阅读 1,375评论 0 0
  • 电线电缆是施工过程不可缺少的材料,一旦电缆起火,将会引起严重火灾和停电事故,此外,电缆燃烧时产生大量浓烟和毒气,不...
    朝阳电缆阅读 265评论 0 0
  • 支教的第三个月到了月末,总感叹时间之快,平淡中发现自己已经对这里的孩子们有了感情。 偶然间发现了简书这个软件。好久...
    猫喵喵啊喵阅读 151评论 0 0