为什么是 Freddy?
解析 JSON 的优雅和安全可能很困难,但 Freddy 会帮您解决。Freddy 是一个用于在 Swift 中解析 JSON 的可重用框架。它有三主要优点。
首先,Freddy 为 Swift 中的 JSON 解析提供了一种类型安全的解决方案。这意味着编译器会帮助您在发送和接收 JSON 时以有助于防止运行时崩溃的方式进行工作。
其次,Freddy 为 JSON 解析提供了一种具有 Swift 泛型、枚举和函数特征的惯用解决方案。这一切都无需记住我们的文档来了解我们的神奇自定义运算符。Freddy 没有任何这些。如果您对用 Swift 编写代码(使用扩展、协议、构造函数等)感到舒适,那么您不仅会了解 Freddy 的组织方式,而且您也会感到舒适地使用 Freddy。
第三,Freddy 为在解析 JSON 时经常出现的错误提供了出色的错误信息。如果您使用一个不存在的键来索引 JSON 对象,您会得到一个有用的错误。如果您的索引超出范围,您会得到一个有用的错误。如果尝试将 JSON 值转换为错误类型,您在这里也会得到一个很好的错误。
所以,Freddy 与 JSON,谁赢了?我们认为胜利者是 Freddy。
用法
本节介绍了 Freddy 的基本用法。您可以在 Wiki 上找到更多关于解析数据、处理错误、将 JSON
实例序列化为 NSData
等的示例。您可以通过阅读 文档 来查看完整的 API。
反序列化:解析原始数据
基本用法
考虑一些示例 JSON 数据
{
"success": true,
"people": [
{
"name": "Matt Mathias",
"age": 32,
"spouse": true
},
{
"name": "Sergeant Pepper",
"age": 25,
"spouse": false
}
],
"jobs": [
"teacher",
"judge"
],
"states": {
"Georgia": [
30301,
30302,
30303
],
"Wisconsin": [
53000,
53001
]
}
}
这里有一个使用 Freddy 解析这些数据的快速示例
let data = getSomeData()
do {
let json = try JSON(data: data)
let success = try json.getBool(at: "success")
// do something with `success`
} catch {
// do something with the error
}
数据加载后,我们创建了一个 JSON
的实例,它是这个框架中的主力。这允许我们访问 JSON 数据中的值。我们 try
因为数据可能是不完整的,解析可能会生成错误。接下来,我们通过在 JSON
上调用 getBool(at:)
方法来访问 "success"
键。这里我们同样 try
,因为访问名为 "success"
的键对应的 json
可能会失败 - 比如如果我们传了一个未知键。此方法接受两个参数,这两个参数都用来定义一个路径到 JSON
实例来找到一个感兴趣的真值。如果 "success"
路径描述中找到一个 Bool
,则 getBool(at:)
返回一个 Bool
。如果路径不指向一个 Bool
,则抛出适当的错误。
使用路径通过下标访问嵌套数据
Freddy 允许使用路径来访问 JSON 结构中更深的元素。例如
let data = getSomeData()
do {
let json = try JSON(data: data)
let georgiaZipCodes = try json.getArray(at: "states","Georgia")
let firstPersonName = try json.getString(at: "people",0,"name")
} catch {
// do something with the error
}
在代码 json.getArray(at: "states","Georgia")
中,键 "states"
和 "Georgia"
描述了从 json
到 Georgia 邮编的路径。Freddy
的术语称此过程为对 JSON 进行“下标操作”。例如在 getArray(at:)
的括号中输入的是一系列用逗号分隔的键和索引,它们描述了到一个感兴趣值的路径。
可以有任意数量的下标,每个下标可以是表示 JSON 中一个元素的命名元素的 String
,或者表示数组中一个元素的 Int
。如果路径中有无效项,例如 JSON 中不存在的索引,会抛出错误。
JSONDecodable:直接反序列化模型
现在,让我们看看一个将数据解析成一个模型类的示例
let data = getSomeData()
do {
let json = try JSON(data: data)
let people = try json.getArray(at: "people").map(Person.init)
// do something with `people`
} catch {
// do something with the error
}
在这里,我们通过 getArray(at:)
方法,而不是使用 getArray(choices:)
方法来获取 "people"
键的值作为数组。这个方法的工作方式与上面看到的 getBool(at:)
方法非常类似。它使用提供给方法的路由来查找数组。如果路径正确,方法将返回一个 Array
的 JSON
。如果路径错误,则会抛出一个适当的错误。
接着,我们可以在那个 JSON
数组上调用 map
。因为 Person
类型遵循 JSONDecodable
协议,我们可以传入 Person
类型的初始化器。这个调用将对数组中的每个元素应用一个初始化器,该初始化器接受一个 JSON
实例,从而生成一个 Person
实例数组。
这就是 JSONDecodable
的样子
public protocol JSONDecodable {
init(json: JSON) throws
}
这是一个相当简单的协议。所有它要求的是,遵循的类型的实现必须有一个初始化器,该初始化器仅以 JSON
实例作为其唯一参数。
为了将这些内容联系起来,这里展示了 Person
类型的外观
public struct Person {
public let name: String
public let age: Int
public let spouse: Bool
}
extension Person: JSONDecodable {
public init(json value: JSON) throws {
name = try value.getString(at: "name")
age = try value.getInt(at: "age")
spouse = try value.getBool(at: "spouse")
}
}
Person
只有几个属性。它通过一个扩展遵循 JSONDecodable
。在这个扩展中,我们实现了一个接受一个 JSON
实例作为唯一参数的 throws
ing 初始化器。在实现中,我们尝试使用三个函数:1) getString(at:)
、2) getInt(at:)
和 3) getBool(at:)
。这些方法的工作方式如你所见。方法接受一个路径,该路径用于在传递给初始化器的 JSON
实例中查找特定类型的值。由于这些路径可能错误,或请求的类型可能不匹配实际的内容,这些方法可能会抛出错误。
序列化
Freddy 的序列化支持集中在 JSON.serialize()
方法上。
基本用法
JSON
枚举支持直接转换为 Data
。
let someJSON: JSON = …
do {
let data: Data = try someJSON.serialize()
} catch {
// Handle error
}
JSONEncodable
:序列化其他对象
虽然大部分你的对象都不是 Freddy.JSON
对象,但是你可以通过首先使用 JSONEncodable.toJSON()
方法将它们转换为 Freddy.JSON
(这是 JSONEncodable
协议的唯一方法),然后再使用 serialize()
方法将 Freddy.JSON
转换为 Data
来将它们序列化为 Data
。
let myObject: JSONEncodable = …
// Object -> JSON -> Data:
let objectAsJSON: JSON = myObject.toJSON()
let data: Data = try objectAsJSON.serialize()
// More concisely:
let dataOneLiner = try object.toJSON().serialize()
Freddy 为常见的 Swift 数据类型提供了定义。为了使你自己的数据类型可序列化,让它们遵循 JSONEncodable
协议并实现该协议的 toJSON()
方法。
extension Person: JSONEncodable {
public func toJSON() -> JSON {
return .dictionary([
"name": .string(name),
"age": .int(age),
"spouse": .bool(spouse)])
}
}
开始使用
Freddy需要支持iOS 8.0,Mac OS X 10.9,watchOS 2.0或tvOS 9.0。目前尚不支持Linux。
您有几种不同的方式来安装Freddy。
Carthage
将我们添加到您的Cartfile
github "bignerdranch/Freddy" ~> 3.0
运行carthage bootstrap
后,将Freddy.framework
添加到应用目标的“链接框架和库”面板中。了解更多。
CocoaPods
将我们添加到您的Podfile
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'Freddy'
然后运行pod install
。
子模块
使用git子模块添加:
git submodule add https://github.com/bignerdranch/Freddy.git Vendor/Freddy
- 将
Freddy.xcodeproj
拖入到您的Xcode项目中。 - 将
Freddy.framework
添加到应用目标的“链接框架和库”面板。
Carthage还可以用来检查依赖项并维护Git子模块状态。
Swift包管理器
在您的Package.swift
中添加我们。
import PackageDescription
let package = Package(
name: "My Nerdy App",
dependencies: [
.Package(url: "https://github.com/bignerdranch/Freddy.git", majorVersion: 3),
]
)
iOS 7
如果您想使用支持iOS 7的Freddy,则需要使用Freddy的旧版本。
设置断点错误
当您开始使用一组新的JSON时,设置错误断点可能会有所帮助。这允许您在断点处探索JSON的结构。特别是,您可能会想要为Freddy的JSON.Error
设置一个断点,以便您可以检查发生了什么错误。
以下是设置此类断点的方法
-
转到断点导航器
-
单击左下角的 "+" 按钮
- 选择 "添加Swift错误断点"
现在您有一个只会在生成Swift错误时触发的断点。但您的程序会在任何Swift错误被抛出时中断。如果只想在Freddy
's JSON.Error
错误发生时中断怎么办呢?
您可以根据需要编辑断点以添加过滤器
-
右键单击您新创建的错误断点
-
选择编辑断点...
-
一个包含 "类型" 文本框的窗口将出现
-
输入
JSON.Error
就是这么简单!现在您有一个只会当抛出类型为JSON.Error
的错误时才触发的错误断点。查看框架的测试以获取更多使用示例,Wiki也有许多非常有用的信息。