如何在 Swift 中优雅地处理 JSON

作者&投稿:胥忽 (若有异议请与网页底部的电邮联系)
如何在 Swift 中优雅地处理 JSON~

下载在这儿下载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?
var object: Dictionary?
注意每一种属性都是一个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
}
地狱星星
地狱星星
翻译于 4个月前
0人顶
顶 翻译的不错哦!
枚举(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)
case JObject(Dictionary)
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,它意味着数组里的每一个元素都是一个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
}
无若
无若
翻译于 4个月前
0人顶
顶 翻译的不错哦!
打印

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

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?
var object: Dictionary?
注意每一种属性都是一个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值。
?
1
2
3
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)
case JObject(Dictionary)
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
}

JSON数据转换
Perfect通过一系列Swift自建数据类型的扩展实现了基本的JSON编码和解码工具。解码是通过在Swift字符串类型基础上实现的扩展。

Perfect 的JSON函数库是开源的,请查看这里下载并安装Perfect对Swift JSON的支持:

https://github.com/PerfectlySoft/Perfect/

请注意虽然Perfect的JSON工具功能强大,但对您的系统而言不是必须的,请根据需要自行选择引用该工具库内的函数。
如果需要使用本系统,请首先在您的源代码开始部分确保PerfectLib库函数已经声明导入:
import PerfectLib

将数据编码为JSON格式
您可以将以下数据类型直接转换为JSON字符串:
String 字符串
Int 整型
UInt 无符号整型
Double 双精度浮点型
Bool 布尔型
Array 任意类型的数组
Dictionary 以字符串为关键词的字典
Optional 可选类型
从JSONConvertibleObject对象继承而来的定制类型
⚠️注意⚠️对于可选类型而言,只有包含上述任意一种类型的Optional类型才是可以直接转换的。对于值为nil的Optionals类型来说,JSON字符串输出结果将会是"null"。
为了实现上述变量类型的编码,请调用上述对象的jsonEncodedString()函数。这个函数是Perfect专门做的扩展。该函数有可能会抛出JSONConversionError.notConvertible无法转换的异常。
举例
let scoreArray: [String:Any] = ["第一名": 300, "第二名": 230.45, "第三名": 150]
let encoded = try scoreArray.jsonEncodedString()

编码结果是如下字符串:
{"第二名":230.45,"第一名":300,"第三名":150}

解码JSON数据
包含JSON格式数据的字符串可以用jsonDecode()函数解码。如果格式有问题,该函数会抛出JSONConversionError.syntaxError语法错误异常。
let encoded = "{\"第二名\":230.45,\"第一名\":300,\"第三名\":150}"
let decoded = try encoded.jsonDecode() as? [String:Any]

对上述字符串的解码将会生成下列内容的字典类型:
["第二名": 230.44999999999999, "第一名": 300, "第三名": 150]

由于解码JSON字符串可能产生任意数据值,因此最常见的方法是用JSON对象(字典)或者数组进行处理。您需要根据结果自行按照预期类型进行转换。
解码后的数据使用
因为解码后的结果总是[String:Any]字典或者[Any]数组,因此您需要其包含的数据转换为预期类型,比如:
var firstPlace = 0
var secondPlace = 0.0
var thirdPlace = 0

let encoded = "{\"第二名\":230.45,\"第一名\":300,\"第三名\":150}"
guard let decoded = try encoded.jsonDecode() as? [String:Any] else {
return
}

for (key, value) in decoded {
switch key {
case "第一名":
firstPlace = value as! Int
case "第二名":
secondPlace = value as! Double
case "第三名":
thirdPlace = value as! Int
default:
break
}
}

print("前三名:\r" + "第一名" + "\(firstPlace)" + " 分\r" + "第二名:" + "\(secondPlace)" + " 分\r" + "第三名:" + "\(thirdPlace)" + " 分")

输出结果为:
前三名:
第一名:300分
第二名:230.45分
第三名:150分

从JSON数据中解码空值
由于JSON的空值是没有类型的,系统会将空值替换为一个JSONConvertibleNull对象。比如:
let jsonString = "{\"第一名\":300,\"第四名\":null,\"第二名\":230.45,\"第三名\":150}"

if let decoded = try jsonString.jsonDecode() as? [String:Any] {
for (key, value) in decoded {
if let value as? JSONConvertibleNull {
print("字段\"\(key)\"为空值")
}
}
}

输出为:
字段"第四名"为空值

可转换为JSON的对象
Perfect的JSON转换工具库提供为定制类的编码解码功能。只要从JSONConvertibleObject基类继承即可,如下示例:
/// 从基类继承为一个可以转化为JSON格式的定制对象。
public class JSONConvertibleObject: JSONConvertible {
/// 默认构造函数
public init() {}
/// 获得JSON键/值
public func setJSONValues(_ values:[String:Any]) {}
/// 根据JSON键/值设置对象属性。
public func getJSONValues() -> [String:Any] { return [String:Any]() }
/// 将对象编码为JSON文本
public func jsonEncodedString() throws -> String {
return try self.getJSONValues().jsonEncodedString()
}
}

任何需要使用JSON编解码的对象都首先要将该对象注册到系统中去。注册工作需要在您的应用程序启动时完成。调用JSONDecoding.registerJSONDecodable函数完成对象注册。该函数定义如下:
public class JSONDecoding {
/// 该函数为基于JSON成员数据定制对象返回一个新的实例。
public typealias JSONConvertibleObjectCreator = () -> JSONConvertibleObject
static public func registerJSONDecodable(name: String, creator: JSONConvertibleObjectCreator)
}

注册对象是需要一个唯一的命名。同样还需要一个creator函数用于在需要时创建一个新的对象实例。
当系统对一个JSONConvertibleObject对象编码时,会调用对象的getJSONValues函数。该函数会返回一个[String:Any]字典,该字典包含了用于给这个对象编码的所有的字段和属性值。这个字典必须要包含一个声明其对象类型的字段。而这个类型字段的值也 必须 是与该对象在程序开始阶段注册的名称一致的名字。对应该属性值的字段由JSONDecoding.objectIdentifierKey属性而定。
当系统解码这样一个对象时,系统会首先寻找JSONDecoding.objectIdentifierKey值,然后在查找之前注册的对象creator构造函数。随后系统会根据这个类型和构造函数自动创建一个新对象并调用setJSONValues(_ values:[String:Any]) 函数设置各字段值。调用该函数会用一个包含所有解码数据的字典作为参数传递过去。这些属性值会与之前由getJSONValues编码函数返回的内容进行匹配。在setJSONValues函数中,对象会恢复所有属性与数据。
下面的例子演示了如何定义一个定制的JSONConvertibleObject对象,以及如何将其转换为一个JSON字符串。然后再进行解码并与原对象进行比较。⚠️注意⚠️在本例子中对象通过调用getJSONValue函数直接把一个命名字段的属性值从字典中抽取出来,而且允许在字典内不包含指定字段的情况下返回一个默认值。
该例子分成了以下几个部分逐一说明。
类定义
class User: JSONConvertibleObject {
static let registerName = "user"
var firstName = ""
var lastName = ""
var age = 0
override func setJSONValues(_ values: [String : Any]) {
self.firstName = getJSONValue(named: "firstName", from: values, defaultValue: "")
self.lastName = getJSONValue(named: "lastName", from: values, defaultValue: "")
self.age = getJSONValue(named: "age", from: values, defaultValue: 0)
}
override func getJSONValues() -> [String : Any] {
return [
JSONDecoding.objectIdentifierKey:User.registerName,
"firstName":firstName,
"lastName":lastName,
"age":age
]
}
}

注册定义好的类信息
// 运行一次即可
JSONDecoding.registerJSONDecodable(name: User.registerName, creator: { return User() })

对象编码:
let user = User()
user.firstName = "Donnie"
user.lastName = "Darko"
user.age = 17

let encoded = try user.jsonEncodedString()

编码后的数据看起来像这样:
{"lastName":"Darko","age":17,"_jsonobjid":"user","firstName":"Donnie"}

对象解码:
guard let user2 = try encoded.jsonDecode() as? User else {
return // 出错
}

// 验证属性值是否一致
XCTAssert(user.firstName == user2.firstName)
XCTAssert(user.lastName == user2.lastName)
XCTAssert(user.age == user2.age)

JSON转换错误
在JSON编码解码过程中,系统可能会抛出一个JSONConversionError转换异常,定义如下:
/// 在JSON编解码过程中可能发生的错误异常。
public enum JSONConversionError: ErrorProtocol {
/// 对象不支持JSON转换。
case notConvertible(Any)
/// 提供的字段不是字符串。
case invalidKey(Any)
/// JSON文本内由语法错误。
case syntaxError
}


庆云县15165617049: 如何在 Swift 中优雅地处理 JSON -
盈苗司利: 下载在这儿下载SwiftyJSON,或者直接在GitHub克隆它: ? 1 git clone https://github.com/lingoer/SwiftyJSON.git 基础用法 SwiftyJSON的使用十分的简单: 典型的NSURLSessionTask抓取...

庆云县15165617049: 如何使用Range截取字符串 -
盈苗司利: Swift中的Ranges和Objective-C中的NSRange有很大的不同,我发现在处理Swift中Ranges相关的问题的时候,总是要花费比我想象的更多的时间.不过,现在回过头来看看,发现Swift中的Ranges的使用还是比较合理的,但是想要正确的使用...

庆云县15165617049: 如何在 Swift 中使用 CommonCrypto 类进行加密 -
盈苗司利: 现在,许多开发者已经不需要在 App 中进行加密处理.即使你在远程服务器上使用了 REST API,通常情况下使用 HTTPS 就可以解决大多数的安全通信问题,剩下的问题可以使用...

庆云县15165617049: case语言怎么用 -
盈苗司利: 具体如下:1、Switch作为选择结构中必不可少的语句也被加入到了Swift中,只要有编程经验的人对Switch语句都不会感到陌生,但苹果对Switch进行了大大的增强,使其拥有其他语言中没有的特性.使用Switch语句很简单2、在这个最简单的...

庆云县15165617049: 项目是swift项目,有一个OC的类需要调用swift类中的全局变量.怎么调用呢? -
盈苗司利: 在swift类中的变量前面添加 @objc,比如 @objc var num: Int = 0 这样子.然后在oc类中就可以使用 . 点号 来调用到了.

庆云县15165617049: 如何在Swift中使用NSError -
盈苗司利: 步骤一:声明NSError变量.一定要加"?",不加或者加"!"都不行.因为使用了optional,所以要用var而不用let.var error: NSError?步骤二:使用的时候在变量前加上"&".NSJSONSerialization.JSONObjectWithData(data!, options: ....

庆云县15165617049: 如何在 swift 中调用 OC 的单例类方法 -
盈苗司利: 一、MySingle类 import Foundation class MySingle{//定义单例的属性var name:String?var age:Int?var height:Double?//定义类方法class func shareInstance()->MySingle{struct qzSingle{static var predicate:dispatch_once_t = 0static var ...

庆云县15165617049: swift在外贸是什么意思 -
盈苗司利: SWIFT又称:环球同业银行金融电讯协会,是国际银行同业间的国际合作组织.而外贸业务中提及的SWIFT多指银行间使用的SWIFT系统.SWIFT系统的使用,使银行的结算提供了安全、可靠、快捷、标准化、自动化的通讯业务,从而大大提高了银行的结算速度.由于SWIFT的格式具有标准化,目前信用证的格式主要都是用SWIFT电文.为了确认买卖双方银行的信息,会在合同中填写双方银行的 SWIFT CODE,以便日后为开信用证或付款提供确切的银行识别.

庆云县15165617049: swift中怎样调用c语言代码 -
盈苗司利: 在Swift中能够直接使用Objective-C语言提供的api (包括系统框架与自己的定制代码),也能够在Objective-C中使用Swift提供的类和api ,还能够在一个工程中同时混合使用Swift 和Objective-C两种语言,两种语言之间能够互通和互用. 任意Objective-...

庆云县15165617049: 苹果Swift语言的前途会怎样 -
盈苗司利: Swift这个新的语言集中了很多其它高级语言的影子,集成了他们的优点.它和Go、Ruby、Python等语言都有些神似.并且它的语法更加接近自然语言,使得编程的过程变得更加简单.这些变化进一步降低了苹果平台上App开发门槛,延续苹果...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网