Swift 进阶【六】编码和解码
将程序内部的数据结构序列化为一些可交换的数据格式,以及反过来将通用的数据格式反序列化为内部使用的数据结构,这在编程中是一项非常常见的任务。Swift 将这些操作称为编码(encoding)和解码(decoing)。Swift 4 的一个主要特性就是定义了一套标准的编码和解码数据的方法,所有的自定义类型都能选择使用这套方法。
概览
Codable 系统(以其基本“协议”命名,而这个协议其实是一个类型别名)的设计主要围绕三个核心目标;
- 普遍性 — 它对结构体,枚举和类都适用。
- 类型安全 — 像是 JSON 这样的可交换格式通常都是弱类型,而你的代码应该要使用强类型数据。
- 减少模板代码 — 在让自定义类型加入这套系统时,应该让开发者尽可能少地写重复的“适配代码”。编译器应该为你自动生成这些代码。
某个类型通过声明自己遵守 Encodable 和/或 Decodable 协议来表明自己具备被序列化和/或反序列化的能力。这两个协议各自只有一个必须实现的方法 - Encodable 定义了 encode(to:)
用来对值自身进行编码,Decodable 指定了一个初始化方法,来从序列化的数据中创建实例:
1 | /// 某个类型可以将自身编码为一种外部表示。 |
因为大多数实现了其中一个协议的类型,也会实现另一个,所以标准库中还提供了 Codable 类型别名,来作为这两个协议组合后的简写:
1 | public typealias Codable = Decodable & Encodable |
标准库中包括 Bool
,数值类型和 String
等所有基本类型,都直接是 Codable 类型。那些含有 Codable 元素的可选值,数组,字典和集合,也都满足 Codable。最后,包括 Data
,Date
,URL
,CGPoint
和 CGRect
在内的许多 Apple 框架中的常用数据类型,也已经适配了 Codable。
Encoding
因为 JSON 是最常见的格式,所以我们来集中研究一下 JSONEncoder
和 JSONDecoder
。
我们先来建两个结构体,一个是封装了坐标的结构体,一个是封装了地点的结构体。
1 | // 坐标 |
接下来我们可以将一个 Placemark
数组编码为 JSON 格式:
1 | let places = [ |
Decoding
这一次我们来看一个复杂一点的,但是在实际应用中,能够经常见到的 JSON 格式。
1 | let jsonStr = |
这里有三层结构,第一层是最外面的一层,第二层是 data
的这一层,第三层是 LocationList
对应的这一层,这一层是一个数组。
下面我们来建立三个结构体,分别对应着三层结构:
第一层 Location
1 | struct Location: Codable { |
第二层 LocationData
1 | struct LocationData: Codable { |
第三层 LocationItem
1 | struct LocationItem: Codable { |
JSON 解码
1 | let jsonDecode = JSONDecoder() |
一种更容易看出 JSON 包含情况的结构体声明
1 | struct Location: Codable { |