Codable

关注
义项:Swift语言的数据编解码协议
Codable

Codable是苹果Swift编程语言标准库中用于数据编解码的一套协议组合,由Encodable与Decodable两个协议通过类型别名组合而成,用于把自定义类型转换为JSON、属性列表(Property List)等外部表示,或从这些外部表示还原为内存中的值。它随Swift 4.0于2017年正式引入,取代了原先依赖NSCoding手工编写编解码代码的做法,编译器可自动合成大部分实现,因而成为Swift生态中网络请求与本地持久化的常用方案。

百科 图文
目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

Codable是Swift标准库中的一个类型别名,其定义为 Codable = Decodable & Encodable,即同时要求类型具备解码与编码两种能力[1]。其中Encodable表示该类型的实例可以写出为外部表示,Decodable表示该类型可以从外部表示中读取并构造实例,二者各自只覆盖单向转换,Codable则把两个方向合并为一个约束[1]。苹果官方文档把它描述为一种能够把自身转换为外部表示、也能从外部表示转换回来的类型。

在使用上,把Codable写在自定义类型的声明之后即表示该类型同时采纳这两个协议;由于它是类型别名,任何同时满足两个协议的类型都会被Codable这一约束接受[1]。Swift标准库还让Optional、Array、Dictionary、Set在元素类型满足条件时以条件遵循的方式自动获得Encodable与Decodable能力,因此嵌套结构通常无需额外处理[2]。

原理

编码与解码由Encoder和Decoder两类协议承担。Encodable要求实现 encode(to:) 方法,把自身的数据写入编码器提供的容器;Decodable要求实现 init(from:) 构造器,从解码器提供的容器中读取数据[3]。容器分为按关键字索引的keyed容器、按顺序索引的unkeyed容器和承载单个值的singleValue容器三种,结构化类型一般在keyed容器中逐属性读写[3]。

属性名与外部表示中的键通过CodingKey协议对应,通常实现为一个名为CodingKeys的枚举,其成员名与属性名一致、原始值给出外部格式中的键名,由此可把Swift风格的下划线命名映射到驼峰命名或相反[4]。只要类型的所有属性都可编码,在声明中写上Codable便可由编译器自动合成CodingKeys以及 init(from:) 与 encode(to:)[3]。

在调用侧,JSONEncoder负责把遵循Codable的值编码为JSON字节数据,JSONDecoder负责把JSON字节数据解码为指定类型;二者的日期字段可通过dateDecodingStrategy或dateEncodingStrategy按ISO 8601、Unix时间戳或自定义格式解析,键名转换策略也可整体设置[5]。属性列表格式则由PropertyListEncoder与PropertyListDecoder处理,它们与JSON的实现方式类似,只是输出为plist[6]。

发展历程

Codable由Swift Archival & Serialization提案(编号SE-0166)确立,该提案在2017年4月完成评审并被接受,评审过程中决定把核心协议下沉到Swift标准库而非留在Foundation中,以便与语言更紧密结合[7]。配套的SE-0167提案定义了JSONEncoder、JSONDecoder以及属性列表编解码器,并在Foundation中补充了编码值无效、类型不匹配、数据损坏、值缺失等错误码,使不同编解码器共享一套错误词汇[6]。

Codable随Swift 4.0正式发布。该版本于2017年9月19日随Xcode 9.0推出,标准库在这一版本中为Optional、Array、Dictionary、Set添加了Encodable与Decodable的条件遵循[8]。在此之前的Swift代码多使用JSONSerialization手工解析字典,或依赖第三方JSON映射库,Codable提供了类型安全、无需额外依赖的原生替代方案[9]。

此后Swift社区持续讨论其替代与改进方案。2025年在Swift官方论坛上出现了关于新一代序列化与反序列化API的设计讨论,目标是在保留易用性的同时提高性能,并计划借助宏来定制自动合成的代码[10]。该讨论指出Codable的部分性能开销来自对存在类型的装箱与动态派发,以及keyed容器需要预先解析负载并分配临时字典[10]。

应用

Codable最常见的用途是处理网络接口返回的JSON数据。应用把服务端响应解码为本地模型类型,再把模型编码后提交给接口,整个过程由JSONDecoder与JSONEncoder完成[4]。把数据保存到磁盘、通过连接传输数据、向API提交数据等任务,都可通过先编码为中间格式再由外部表示承载的方式实现[11]。

在自定义映射方面,当属性名与外部键名不一致时可使用CodingKeys枚举指定映射关系;属性可能缺失时可改用可选类型或调用decodeIfPresent在键不存在或值为空时返回nil[7]。对于结构不完全对应的负载,例如外部数据把地址放在子对象中而本地类型把街道、城市平铺为属性,可以请求nestedContainer取出子对象再逐字段读取[7]。

局限

Codable基于值语义设计,对引用语义的对象图支持有限。带有别名(同一对象被多处引用)的对象图在编解码时会被复制,形成环的对象图则无法解码,因为递归会无限进行下去[12]。因此它并不适合直接替代NSCoding来处理任意的类对象归档场景[12]。

自动合成的解码逻辑要求每个非可选属性都必须在负载中出现,缺失对应键时会抛出keyNotFound错误;负载中多出的字段则会被忽略[7]。此外,属性在声明处写的默认值不会在自动合成的解码流程中生效,因为合成的构造器直接调用decode并要求键存在[13]。数组解码中只要有一个元素格式不符,整个数组的解码就会失败,无法跳过个别脏数据[13]。

受Swift类型系统限制,Any与[String: Any]这类动态类型本身不遵循Decodable,无法直接放入Codable模型中,处理高度动态的负载需要额外的包装类型或自定义实现[13]。编解码时也必须在调用处指定具体类型,只知协议而不知具体类型时无法解码,因为解码器需要知道要构造的实际类型[14]。在性能方面,编解码协议的存在类型开销与keyed容器的预解析分配会产生额外的运行时与内存成本[10]。

参见

  • Encodable —— Codable的组成协议之一,规定类型可以编码为外部表示。

  • Decodable —— Codable的组成协议之一,规定类型可以从外部表示解码而来。

  • JSONEncoder —— Foundation提供的编码器,把遵循Codable的值写成JSON数据。

  • JSONDecoder —— Foundation提供的解码器,把JSON数据还原为遵循Codable的类型。

  • CodingKey —— 用于把类型属性名与外部表示中的键对应起来的协议。

  • NSCoding —— Objective-C时代的归档协议,Codable在Swift中部分取代了它的用途。

参考资料

  1. Codable | Documentation [引用日期2026-10-14]
  2. CHANGELOG [引用日期2026-10-14]
  3. Swift Archival & Serialization [引用日期2026-10-14]
  4. encoding-and-decoding-custom-types [引用日期2026-10-14]
  5. name: swift-codable [引用日期2026-10-14]
  6. Swift Encoders [引用日期2026-10-14]
  7. swift.org 上的网页 [引用日期2026-10-14]
  8. softwareheritage.org 上的网页 [引用日期2026-10-14]
  9. 【IOS】Codable [引用日期2026-10-14]
  10. mjtsai.com 上的网页 [引用日期2026-10-14]
  11. 编码和解码自定类型 | Apple Developer Documentation [引用日期2026-10-14]
  12. Revisions to Can NSCoding and Codable co-exist? [引用日期2026-10-14]
  13. 类型安全的代价与妥协:从 HandyJSON 内存黑客到现代 Swift JSON 解析的架构演进 [引用日期2026-10-14]
  14. apple.com 上的网页 [引用日期2026-10-14]
词条评价
词条统计

浏览次数:2 次

阅读量:0 次 · 阅读完成量:0 次

最近更新:2026-10-13T20:43:58Z

历史版本

本条目引用的词条
Encodable Decodable JSONEncoder JSONDecoder CodingKey NSCoding