Freddy 3.0.3

Freddy 3.0.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2019 年 11 月
SwiftSwift 版本3.0
SPM支持 SPM

Zachary WaldowskiZachary WaldowskiDavid House 维护。



Freddy 3.0.3

  • by
  • Matt Mathias,John Gallagher 及 Zachary Waldowski

为什么是 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:) 方法非常类似。它使用提供给方法的路由来查找数组。如果路径正确,方法将返回一个 ArrayJSON。如果路径错误,则会抛出一个适当的错误。

接着,我们可以在那个 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 实例作为唯一参数的 throwsing 初始化器。在实现中,我们尝试使用三个函数: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

子模块

  1. 使用git子模块添加:git submodule add https://github.com/bignerdranch/Freddy.git Vendor/Freddy
  2. Freddy.xcodeproj拖入到您的Xcode项目中。
  3. 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设置一个断点,以便您可以检查发生了什么错误。

以下是设置此类断点的方法

  1. 转到断点导航器

  2. 单击左下角的 "+" 按钮

Breakpoint navigator

  1. 选择 "添加Swift错误断点"

Add Error Breakpoint

现在您有一个只会在生成Swift错误时触发的断点。但您的程序会在任何Swift错误被抛出时中断。如果只想在Freddy's JSON.Error错误发生时中断怎么办呢?

您可以根据需要编辑断点以添加过滤器

  1. 右键单击您新创建的错误断点

  2. 选择编辑断点...

Edit Breakpoint

  1. 一个包含 "类型" 文本框的窗口将出现

  2. 输入 JSON.Error

Error Type

就是这么简单!现在您有一个只会当抛出类型为JSON.Error的错误时才触发的错误断点。查看框架的测试以获取更多使用示例,Wiki也有许多非常有用的信息。