JSONUtilities

Build Status codecov.io Carthage Compatible Swift Version

轻松加载 JSON 对象并将它们解码为结构体或类。 json(atKeyPath:) 函数会从常量或变量定义中推断类型以进行解码,这意味着无需类型转换。在解码 JSON 时,字符串键和键路径(以点 . 分隔的键)均受支持。

安装

CocoaPods

将行 pod 'JSONUtilities' 添加到您的 Podfile

Carthage

将行 github "lucianomarisi/JSONUtilities" 添加到您的 Cartfile

手动

Sources 文件夹中的文件添加到您的 Xcode 项目中。

Swift Package Manager

将行 .Package(url: "https://github.com/lucianomarisi/JSONUtilities", majorVersion: 3) 添加到您的 Package.swift

支持的类型

JSON 原始类型

JSON 原始类型数组

自定义 JSON 对象和自定义 JSON 对象数组

例如,如果 MyClassMyStruct 遵循 JSONObjectConvertible 协议

带有 JSONKey 的字典

String 已经遵循 JSONKey。通过使枚举键遵循 JSONKey 也很容易创建枚举键,这需要一个 var key: String { get } 和一个 init?(rawValue: String),RawRepresentable 已经遵循了,例如

enum MyEnum: String, JSONKey {
	case one
	case two
	
	var key: String {
		return rawValue
	}
}

InvalidItemBehaviour

当解码数组或字典时,可以传递 invalidItemBehaviour 参数,该参数控制在解码子项时发生错误时会发生什么

KeyPath

每个 json(atKeyPath:) 函数都接受一个 KeyPath。这是一个具有 2 种情况的枚举

KeyPath 可以使用字符串字面量初始化。这样做时,如果存在任何 .,它将被视为键路径而不是简单键。

当提供键路径时,int 允许按索引查找数组中的值。例如:"myArray.1" 字符串字面量将查找键 myArray,然后查找该值(如果该值是数组)的第 2 项(索引从 0 开始)

JSON 加载示例

从文件

let filename = "myjsonfile"
let dictionary: [String: AnyObject] = try JSONDictionary.from(filename: filename)

从数据

let data: Data = ...
let dictionary: [String: AnyObject] = try JSONDictionary.from(jsonData: data)

JSON 解码示例

考虑一个表示人的 JSON 对象

{
  "name" : "John Doe",
  "age" : 24,
  "weight" : 72.4
}

内联解码 JSON

let jsonDictionary = try JSONDictionary.from(filename: "person.json")
let name: String = try jsonDictionary.json(atKeyPath: "name")
let age: Int = try jsonDictionary.json(atKeyPath: "age")
let weight: Int = try jsonDictionary.json(atKeyPath: "weight")
let profession: String? = jsonDictionary.json(atKeyPath: "profession") // Optional decoding

解码结构体或类

struct Person { //OR class Person {

  let name: String
  let age: Int
  let weight: Double
  let profession: String?

  init(jsonDictionary: JSONDictionary) throws {
    name = try jsonDictionary.json(atKeyPath: "name")
    age = try jsonDictionary.json(atKeyPath: "age")
    weight = try jsonDictionary.json(atKeyPath: "weight")
    profession = jsonDictionary.json(atKeyPath: "profession")
  }

}

通过遵循 JSONObjectConvertible 协议解码嵌套的结构体或类

考虑一个公司 JSON 对象

{
    "name" : "Working name LTD.",
    "employees": [
        {
            "name": "John Doe",
            "age": 24,
            "weight": 72.4
        },
        {
            "name": "Jane Doe",
            "age": 22,
            "weight": 70.1
        }
    ]
}

Company 结构体可以通过使 Person 结构体/类遵循 JSONObjectConvertible 协议来解码 Person 结构体/类的数组

struct Company {
  let name: String
  let employees: [Person]

  init(jsonDictionary: JSONDictionary) throws {
    name = try jsonDictionary.json(atKeyPath: "name")
    employees = try jsonDictionary.json(atKeyPath: "employees")
  }
}

通过遵循 JSONPrimitiveConvertible 来支持自定义原始类型

任何类型都可以扩展 JSONPrimitiveConvertible 协议以允许解码。例如扩展 URL请注意,此扩展是开箱即用的

extension URL: JSONPrimitiveConvertible {

  public typealias JSONType = String

  public static func from(jsonValue: String) -> Self? {
    return self.init(string: jsonValue)
  }

}

let urlDictionary = ["url": "www.google.com"]
let url: URL = try! urlDictionary.json(atKeyPath: "url") // www.google.com

也可以拥有 JSONPrimitiveConvertible 值的数组,例如

let urlsDictionary = ["urls": ["www.google.com", "www.yahoo.com"]]
let urls: [URL] = try! urlsDictionary.json(atKeyPath: "urls") // [www.google.com, www.yahoo.com]