图片来自:https://unsplash.com/photos/f...
本文作者:无帆
业界常用的几种方案
手动解码方案,如 Unbox(DEPRECATED)
Swift 早期普遍采用的方案,类似的还有 ObjectMapper
该方案需要使用者手动编写解码逻辑,使用成本比较高;目前已被 Swift 官方推出的 Codable 取代
示例:
struct User {
let name: String
let age: Int
}
extension User: Unboxable {
init(unboxer: Unboxer) throws {
self.name = try unboxer.unbox(key: "name")
self.age = try unboxer.unbox(key: "age")
}
}
阿里开源的 HandyJSON
HandyJSON 目前依赖于从 Swift Runtime 源码中推断的内存规则,直接对内存进行操作。
在使用方面,不需要繁杂的定义,不需要继承自 NSObject,声明实现了协议即可
示例:
class Model: HandyJSON {
var userId: String = ""
var nickname: String = ""
required init() {}
}
let jsonObject: [String: Any] = [
"userId": "1234",
"nickname": "lilei",
]
let model = Model.deserialize(from: object)
但是存在兼容和安全方面的问题,由于强依赖内存布局规则,Swift 大版本升级时可能会有稳定性问题。同时由于要在运行时通过反射解析数据结构,会对性能有一定影响
基于 Sourcery 的元编程方案
Sourcery 是一款 Swift 代码生成器,使用 SourceKitten 解析 Swift 源码,根据 Stencil 模版生成最终代码
可定制能力非常强,基本可以满足我们所有的需求
示例:
定义了 AutoCodable
协议,并且让需要被解析的数据类型遵循该协议
protocol AutoCodable: Codable {}
class Model: AutoCodable {
// sourcery: key = "userID"
var userId: String = ""
var nickname: String = ""
required init(from decoder: Decoder) throws {
try autoDecodeModel(from: decoder)
}
}
之后通过 Sourcery 生成代码,这个过程 Sourcery 会扫描所有代码,对实现了 AutoCodable
协议的类/结构体自动生成解析代码
// AutoCodable.generated.swift
// MARK: - Model Codable
extension Model {
enum CodingKeys: String, CodingKey {
case userId = "userID"
case nickname
}
// sourcery:inline:Model.AutoCodable
public func autoDecodeModel(from decoder: Decoder) throws {
// ...
}
}
如上所示,还可以通过代码注释(注解)来实现键值映射等自定义功能,但是需要对使用者有较强的规范要求。其次在组件化过程中需要对每个组件进行侵入/改造,内部团队可以通过工具链解决,作为跨团队通用方案可能不是太合适
Swift build-in API Codable
Swift 4.0 之后官方推出的 JSON 序列化方案,可以理解为 Unbox+Sourcery 的组合,编译器会根据数据结构定义,自动生成编解码逻辑,开发者使用特定的 Decoder/Encoder 对数据进行转化处理。
Codable 作为 Swift 官方推出的方案,使用者可以无成本的接入。不过在具体实践过程中,碰到了一些问题
- Key 值映射不友好,例如以下情况: