SwiftyJSON 5.0.2

SwiftyJSON 5.0.2

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布最新发布2024年4月
SPM支持 SPM

Maintained by tangplin, Ruoyu Fu, Kyle Fang, Zigii Wong.



  • lingoer 和 tangplin

SwiftyJSON

Carthage compatible CocoaPods Platform Reviewed by Hound

SwiftyJSON 让您在 Swift 中轻松处理 JSON 数据。

平台 构建状态
*OS Travis CI
Linux Build Status
  1. 为什么 Swift 中典型的 JSON 处理方式不是很好
  2. 要求
  3. 集成
  4. 用法
  5. 与 Alamofire 一起使用
  6. 与 Moya 一起使用
  7. SwiftyJSON 模型生成器

中文介绍

为什么 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 Wrapping 的问题。它会自动为您处理。

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+)

您可以使用CocoaPods通过将其添加到您的Podfile中来安装SwiftyJSON

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    pod 'SwiftyJSON', '~> 4.0'
end

Carthage (iOS 8+, OS X 10.9+)

您可以使用Carthage通过将其添加到您的Cartfile中来安装SwiftyJSON

github "SwiftyJSON/SwiftyJSON" ~> 4.0

如果您使用Carthage构建依赖项,请确保您已将SwiftyJSON.framework添加到目标中“链接的框架和库”部分,并在您的Carthage框架复制构建阶段中包含了它们。

Swift Package Manager

您可以通过在您的Package.swift文件中添加正确的描述来使用Swift Package Manager来安装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+)

要将此库手动用于您的项目,您可能

  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)
}

索引器

// 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 是一个数组,第一个元素始终是一个字符串。

// 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(无效 JSON),同时,ErrorDomain 正在被 SwiftyJSONError.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 中会将仅存在于其他 JSON 中的所有非现有值添加到原始 JSON 中。

如果两个 JSON 对同一个键都有值,大多数情况下,这个值会覆盖原始 JSON 中的值,但有几种特殊情况会提供一些特殊处理

  • 如果两个值都是 JSON.Type.array,则从其他 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 一种
  • 使用自定义的一种,它将很好地处理可选性并以 "null" 的形式表示 nil
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。

查看:Alamofire-SwiftyJSON

使用 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 模型的工具