CodablePlus

围绕 Swift Codable 实现的一系列扩展。

用法

解码/编码 Dictionary<String, Any> & Array<Any>

Swift 中的 Any 类型不符合 Codable 协议,因为它能表示任何类型(无论是否可编码)。但是,我们会在某些情况下遇到 JSON 对象由 Dictionary<String, Any> 表示的情况,这里的 Any 被限制为一组已知的、支持 codable 的类型。

现在可以将 JSON 对象反序列化/序列化为/从它们的 swift 对等物。一个可能使用这种情况的主要例子是 API,它们可能期望一个“合理”定义的响应,但可能会使用随机或运行时未知的键。在这种情况下,类型安全无法满足,但数据仍然有价值。

现在可以与以下 Container 定义和 JSON 代码片段进行交互

struct Container: Codable {
    var dictionary: [String: Any]

    private enum CodingKeys: String, CodingKey {
        case dictionary
    }

    init(dictionary: [String: Any]) {
        self.dictionary = dictionary
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        dictionary = try container.decode([String: Any].self, forKey: .dictionary)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(dictionary, forKey: .dictionary)
    }
}
{
  "dictionary": {
    "aString": "This is a string.",
    "aInt": 47,
    "aDouble": 55.88,
    "aBool": true,
    "aArray": ["String", 123, 123.456, false],
    "aDictionary": {
      "name": "Bob",
      "age": 69
    }
  }
}

这些相同的示例可以应用于 Array<Any>,其中 Any 表示 JSON 兼容的原语之一

以及这些容器,当由相同的原始类型组成时。

解码多个键

在项目的积极开发期间,API 规范经常会更改,或者可能在一个端点到另一个端点之间不一致。如果我们的 Swift 模型可以保持一致,但支持解码多个可能的实体模型,那将非常方便。使用 Codable+,这是可能的。

给定以下内容

struct CompanyV1: Decodable {
    var name: String
    var employees: Int
}

struct CompanyV2: Decodable {
    var companyName: String
    var employees: Int
    var ceoName: String

    private enum CodingKeys: String, CodingKey {
        case name
        case companyName
        case employees
        case ceoName
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        companyName = try container.decode(String.self, forKeys: [.name, .companyName])
        employees = try container.decode(Int.self, forKey: .employees)
        ceoName = try container.decodeIfPresent(String.self, forKey: .ceoName) ?? ""
    }
}

let schema1json = """
{
    "name": "Apple",
    "employees": 42000
}
"""

let schema2json = """
{
    "companyName": "Microsoft",
    "employees": 600000,
    "ceoName": "Satya Nadella"
}
"""

注意到 init(from:) 方法中的 companyName = 吗?这指定了多个可能的 CodingKey。现在我们的 CompanyV2 模型支持解码我们的 CompanyV1 模式。

安装

Codable+ 使用 Swift Package Manager 分发。要将其安装到项目中,请将其作为依赖项添加到您的 Package.swift 清单中

let package = Package(
    ...
    dependencies: [
        .package(url: "https://github.com/richardpiazza/CodablePlus.git", from: "1.0.0")
    ],
    ...
)

然后在您想要使用它的任何地方导入 Codable+

import CodablePlus

灵感来源

Codable+ 的发展和灵感来源于互联网上的一些帖子