MetaCodable

API Docs Swift Package Manager Compatible CocoaPods Compatible Swift Platforms CI/CD CodeFactor codecov

使用宏来增强 SwiftCodable 实现。

概述

MetaCodable 框架暴露了自定义宏,可用于生成动态 Codable 实现。该框架的核心是 Codable() 宏,它在其他宏提供的数据的辅助下生成实现。

MetaCodable 旨在通过提供以下内置功能来增强您的 Codable 实现

查看此宏的限制.

要求

平台 最低 Swift 版本 安装 状态
iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ 5.9 Swift Package Manager, CocoaPods 完全测试
Linux 5.9 Swift Package Manager 完全测试
Windows 5.9.1 Swift Package Manager 完全测试

安装

Swift Package Manager

Swift Package Manager 是一种用于自动化 Swift 代码分发的工具,已集成到 swift 编译器中。

设置好 Swift 包后,将 MetaCodable 作为依赖项添加到 Package.swiftdependencies 值中非常简单。

.package(url: "https://github.com/SwiftyLab/MetaCodable.git", from: "1.0.0"),

然后,通过将其添加到 targetdependencies 值中,可以将 MetaCodable 模块产品作为依赖项添加到您选择的 target 中。

.product(name: "MetaCodable", package: "MetaCodable"),

CocoaPods

CocoaPods 是 Cocoa 项目的依赖项管理器。有关使用和安装说明,请访问他们的网站。 要使用 CocoaPods 将 MetaCodable 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它

pod 'MetaCodable'

用法

MetaCodable 允许摆脱某些典型的 Codable 实现中经常需要的样板代码,并具有以下功能

每个变量的自定义 `CodingKey` 值声明,而无需您为所有字段编写。

例如,在官方 文档 中,要为 Landmark 类型的 2 个字段定义自定义 CodingKey,您必须编写

struct Landmark: Codable {
    var name: String
    var foundingYear: Int
    var location: Coordinate
    var vantagePoints: [Coordinate]

    enum CodingKeys: String, CodingKey {
        case name = "title"
        case foundingYear = "founding_date"
        case location
        case vantagePoints
    }
}

但是使用 MetaCodable,您只需要编写以下内容

@Codable
struct Landmark {
    @CodedAt("title")
    var name: String
    @CodedAt("founding_date")
    var foundingYear: Int

    var location: Coordinate
    var vantagePoints: [Coordinate]
}
为嵌套的 `CodingKey` 值创建扁平化的模型。

例如,在官方 文档 中,要解码像这样的 JSON

{
  "latitude": 0,
  "longitude": 0,
  "additionalInfo": {
      "elevation": 0
  }
}

你必须编写所有这些样板代码

struct Coordinate {
    var latitude: Double
    var longitude: Double
    var elevation: Double

    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
        case additionalInfo
    }

    enum AdditionalInfoKeys: String, CodingKey {
        case elevation
    }
}

extension Coordinate: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        latitude = try values.decode(Double.self, forKey: .latitude)
        longitude = try values.decode(Double.self, forKey: .longitude)

        let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
        elevation = try additionalInfo.decode(Double.self, forKey: .elevation)
    }
}

extension Coordinate: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)

        var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
        try additionalInfo.encode(elevation, forKey: .elevation)
    }
}

但是使用 MetaCodable,您只需要编写以下内容

@Codable
struct Coordinate {
    var latitude: Double
    var longitude: Double

    @CodedAt("additionalInfo", "elevation")
    var elevation: Double
}

您甚至可以使用 CodedIn 宏进一步最小化,因为最终的 CodingKey 值与字段名称相同

@Codable
struct Coordinate {
    var latitude: Double
    var longitude: Double

    @CodedIn("additionalInfo")
    var elevation: Double
}
在解码失败时提供默认值。

您可以提供一个默认值,而不是在缺少数据或类型不匹配时抛出错误,该默认值将在这种情况下分配。 以下使用 MetaCodable 的定义

@Codable
struct CodableData {
    @Default("some")
    let field: String
}

当提供空的 JSON ({}) 或具有类型不匹配的 JSON ({ "field": 5 }) 时,将不会抛出任何错误。 在这种情况下,将分配默认值。

此外,可以生成成员初始化程序,该程序使用此默认值作为该字段。

@Codable
@MemberInit
struct CodableData {
    @Default("some")
    let field: String
}

生成的成员初始化程序将如下所示

init(field: String = "some") {
    self.field = field
}
使用或创建自定义助手以提供自定义解码/编码。

该库提供了以下助手,可满足常见的自定义解码/编码需求

还有更多,请参阅 HelperCoders 的完整文档以获取更多详细信息。

您甚至可以通过遵守 HelperCoder 来创建自己的。

以外部/内部/相邻标记的形式或缺少任何标记的形式表示具有变体的数据,使用单个枚举,每个 case 作为变体,或使用协议类型(不支持缺少标记),该协议类型因跨模块的一致性而异。

例如,虽然 Swift 编译器仅生成假设外部标记枚举的实现,但只有以下数据

[
  {
    "load": {
      "key": "MyKey"
    }
  },
  {
    "store": {
      "key": "MyKey",
      "value": 42
    }
  }
]

可以使用当前编译器实现的以下 enum 来表示

enum Command {
    case load(key: String)
    case store(key: String, value: Int)
}

MetaCodable 允许以上 enum 表示以下两种格式的数据

[
  {
    "type": "load",
    "key": "MyKey"
  },
  {
    "type": "store",
    "key": "MyKey",
    "value": 42
  }
]
[
  {
    "type": "load",
    "content": {
      "key": "MyKey"
    }
  },
  {
    "type": "store",
    "content": {
      "key": "MyKey",
      "value": 42
    }
  }
]

有关 API 详细信息和高级用例,请参阅 MetaCodableHelperCoders 的完整文档。 此外,查看限制

贡献

如果您希望贡献更改、提出任何改进建议,请查看我们的贡献指南,检查是否有未解决的问题(是否已在处理中),或者打开一个拉取请求

许可

MetaCodable 在 MIT 许可下发布。 有关详细信息,请参见 LICENSE