SwiftyJSON
SwiftyJSON 使在 Swift 中处理 JSON 数据变得简单。
平台 | 构建状态 |
---|---|
*OS | |
Linux |
为什么 Swift 中典型的 JSON 处理不好?
Swift 非常注重类型。虽然显式类型可以让我们避免错误,但在处理 JSON 等类型本质上隐式的领域时,它就变得痛苦。
以 Twitter API 为例。假设我们想在 Swift 中检索某个推文的用户 "name" 值(根据 Twitter 的 API)。
代码看起来像这样
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
}
不用担心 Optional Wrapper 的事情。它会自动为您处理。
let json = JSON(data: dataFromNetworking)
let result = json[999999]["wrong_key"]["wrong_name"]
if let userName = result.string {
//Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety
} else {
//Print the error
print(result.error)
}
要求
- iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
- Xcode 8
集成
CocoaPods (iOS 8+, OS X 10.9+)
您可以通过将 SwiftyJSON
添加到您的 Podfile
中来使用 CocoaPods 进行安装
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'SwiftyJSON', '~> 4.0'
end
Carthage (iOS 8+, OS X 10.9+)
您可以通过将 SwiftyJSON
添加到您的 Cartfile
中来使用 Carthage 进行安装
github "SwiftyJSON/SwiftyJSON" ~> 4.0
如果您使用 Carthage 构建依赖项,请确保已将 SwiftyJSON.framework
添加到目标的“链接框架和库”部分,并将其包括在 Carthage 框架的复制构建阶段中。
Swift 包管理器
您可以将适当的描述添加到您的 Package.swift
文件中来使用 Swift 包管理器 安装 SwiftyJSON
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "YOUR_PROJECT_NAME",
dependencies: [
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "4.0.0"),
]
)
然后,每次准备好后,都运行 swift build
手动 (iOS 7+, OS X 10.9+)
要手动在项目中使用此库,您可能需要以下操作
- 对于项目,只需将 SwiftyJSON.swift 拖动到项目树中
- 对于工作空间,包括整个 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)
}
下标
// Getting a double from a JSON Array
let name = json[0].double
// Getting an array of string from a JSON Array
let arrayNames = json["users"].arrayValue.map {$0["name"].stringValue}
// Getting a string from a JSON Dictionary
let name = json["name"].stringValue
// Getting a string using a path to the element
let path: [JSONSubscriptType] = [1,"list",2,"name"]
let name = json[path].string
// Just the same
let name = json[1]["list"][2]["name"].string
// Alternatively
let name = json[1,"list",2,"name"].string
// With a hard way
let name = json[].string
// With a custom way
let keys:[JSONSubscriptType] = [1,"list",2,"name"]
let name = json[keys].string
循环
// If json is .Dictionary
for (key,subJson):(String, JSON) in json {
// Do something you want
}
即使是 JSON 是一个数组,第一个元素总是 String
// If json is .Array
// The `index` is 0..<json.count's string value
for (index,subJson):(String, JSON) in json {
// Do something you want
}
错误
SwiftyJSON 4.x
SwiftyJSON 4.x 引入了一个名为 SwiftyJSONError
的枚举类型,其中包括 unsupportedType
、indexOutOfBounds
、elementTooDeep
、wrongType
、notExist
和 invalidJSON
,同时正在用 SwiftyJSONError.errorDomain
替换 ErrorDomain
。注意:旧错误类型在 SwiftyJSON 4.x 中已弃用,将在未来版本中删除。
SwiftyJSON 3.x
使用下标在数组或字典中获取/设置值
如果JSON是
- 一个数组,应用可能会因为“索引超出范围”而崩溃。
- 一个字典,它将无理由地分配给
nil
。 - 不是数组或字典,应用可能会因为一个“未识别的选择器”异常而崩溃。
在SwiftyJSON中永远不会发生这种情况。
let json = JSON(["name", "age"])
if let name = json[999].string {
// Do something you want
} else {
print(json[999].error!) // "Array[999] is out of bounds"
}
let json = JSON(["name":"Jack", "age": 25])
if let name = json["address"].string {
// Do something you want
} else {
print(json["address"].error!) // "Dictionary["address"] does not exist"
}
let json = JSON(12345)
if let age = json[0].string {
// Do something you want
} else {
print(json[0]) // "Array[0] failure, It is not an array"
print(json[0].error!) // "Array[0] failure, It is not an array"
}
if let name = json["name"].string {
// Do something you want
} else {
print(json["name"]) // "Dictionary[\"name"] failure, It is not an dictionary"
print(json["name"].error!) // "Dictionary[\"name"] failure, It is not an dictionary"
}
可选获取器
// NSNumber
if let id = json["user"]["favourites_count"].number {
// Do something you want
} else {
// Print the error
print(json["user"]["favourites_count"].error!)
}
// String
if let id = json["user"]["name"].string {
// Do something you want
} else {
// Print the error
print(json["user"]["name"].error!)
}
// Bool
if let id = json["user"]["is_translator"].bool {
// Do something you want
} else {
// Print the error
print(json["user"]["is_translator"].error!)
}
// Int
if let id = json["user"]["id"].int {
// Do something you want
} else {
// Print the error
print(json["user"]["id"].error!)
}
...
非可选获取器
非可选获取器名称为xxxValue
// If not a Number or nil, return 0
let id: Int = json["id"].intValue
// If not a String or nil, return ""
let name: String = json["name"].stringValue
// If not an Array or nil, return []
let list: Array<JSON> = json["list"].arrayValue
// If not a Dictionary or nil, return [:]
let user: Dictionary<String, JSON> = json["user"].dictionaryValue
设置器
json["name"] = JSON("new-name")
json[0] = JSON(1)
json["id"].int = 1234567890
json["coordinate"].double = 8766.766
json["name"].string = "Jack"
json.arrayObject = [1,2,3,4]
json.dictionaryObject = ["name":"Jack", "age":25]
原始对象
let rawObject: Any = json.object
let rawValue: Any = json.rawValue
//convert the JSON to raw NSData
do {
let rawData = try json.rawData()
//Do something you want
} catch {
print("Error \(error)")
}
//convert the JSON to a raw String
if let rawString = json.rawString() {
//Do something you want
} else {
print("json.rawString is nil")
}
存在性
// shows you whether value specified in JSON or not
if json["name"].exists()
字面量可转换性
有关字面量可转换性的更多信息,请参阅:Swift 字面量可转换性
// StringLiteralConvertible
let json: JSON = "I'm a json"
/ /IntegerLiteralConvertible
let json: JSON = 12345
// BooleanLiteralConvertible
let json: JSON = true
// FloatLiteralConvertible
let json: JSON = 2.8765
// DictionaryLiteralConvertible
let json: JSON = ["I":"am", "a":"json"]
// ArrayLiteralConvertible
let json: JSON = ["I", "am", "a", "json"]
// With subscript in array
var json: JSON = [1,2,3]
json[0] = 100
json[1] = 200
json[2] = 300
json[999] = 300 // Don't worry, nothing will happen
// With subscript in dictionary
var json: JSON = ["name": "Jack", "age": 25]
json["name"] = "Mike"
json["age"] = "25" // It's OK to set String
json["address"] = "L.A." // Add the "address": "L.A." in json
// Array & Dictionary
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"]
json[path] = "that"
// With other JSON objects
let user: JSON = ["username" : "Steve", "password": "supersecurepassword"]
let auth: JSON = [
"user": user.object, // use user.object instead of just user
"apikey": "supersecretapitoken"
]
合并
可以将一个JSON合并到另一个JSON中。将JSON合并到另一个JSON中会将other
JSON中仅存在且在原始JSON中不存在的所有值添加到原始JSON中。
如果两个JSON都包含相同键的值,通常 这个值会在原始JSON中被覆盖,但有两种情况提供了特殊的处理方式
- 如果两个值都是
JSON.Type.array
类型,则从other
JSON中找到的数组成员将被追加到原始JSON的数组值中。 - 如果两个值都是
JSON.Type.dictionary
类型,则两个JSON值将按照封装JSON的合并方式进行合并。
如果JSON中两个字段的类型不同,则值总是会被覆盖。
合并有两种不同的方式:merge
会修改原始JSON,而 merged
则在一个副本上以非破坏性方式操作。
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, method: .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)
}
}
我们还提供了一个Alamofire的扩展,用于将NSData序列化为SwiftyJSON JSON。
Moya 一起工作
与SwiftyJSON将数据解析为JSON
let provider = MoyaProvider<Backend>()
provider.request(.showProducts) { result in
switch result {
case let .success(moyaResponse):
let data = moyaResponse.data
let json = JSON(data: data) // convert network data to json
print(json)
case let .failure(error):
print("error: \(error)")
}
}
SwiftyJSON模型生成器
生成SwiftyJSON模型的工具