MacroCodableKit 增强了您在 Swift 中的 Codable
体验,利用宏生成精确高效的代码,零额外内存分配,这得益于纯(静态)函数的使用。它是一个全面的解决方案,提供对 AllOf
、OneOf
和可自定义的 CodingKeys
的支持,扩展了原生的 Codable 功能,以无缝地跟上 OpenAPI 规范。
使用属性包装器来实现 Codable
是另一种方法,它非常灵活,并且肯定会大大减少样板代码,但同时它也有其局限性
OneOf
或 AllOf
这样的来自 OpenAPI 的功能,这些功能在当今的 API 中非常常见@propertyWrapper
更改 CodingKeys
@propertyWrapper
是属性旁边的一个附加结构体,因此您最终可能会比需要的分配多一倍的内存@propertyWrapper
应该是可设置的,所以您不能使用 let
,并且您可能会最终使用 private(set)
虽然有一个 提案 允许
@propertyWrappers
使用let
,我希望它最终能够完成
使用 宏 来处理 Codable
可以实现零额外分配、不可变属性,并在一个工具中实现任何理想的 Codable 策略 - MacroCodableKit,它提供了来自 OpenAPI 规范的 OneOf
和 AllOf
编码实现,并允许通过注解更改 CodingKeys
。
CodingKey(_ key: String)
注解指定自定义编码键。OmitCoding
忽略某些属性的编码。SafeDecoding
以安全的方式处理数组和字典。CustomCodingDecoding.errorHandler
处理忽略的解码错误;使用 CustomCodingEncoding.errorHandler
处理编码错误。... 以及更多!
使用 @Codable
注解一个结构体,如果在属性上没有额外的注解,它将生成默认的 Codable
一致性
注意 不要自己遵循
Codable
协议,这将阻止宏生成代码
@Codable
struct User {
let birthday: Double
let name: String
let isVerified: Bool
}
让我们将 birthday
转换为 Date
,更改 isVerified
的编码键,并将其默认设置为 false
注意 如果您不需要编码,则仅遵循
@Decodable
@Decodable
struct User {
@ValueStrategy(ISO8601Default)
let birthday: Date
let name: String
@CodingKey("is_verified")
@DefaultValue(BoolFalse)
let isVerified: Bool
}
// json: { "birthday": 1696291200.0, "name": "Mikhail" }
// is_verified is not specified, so the default value is "false" as specified by `@DefaultValue`
@AllOfCodable 描述了 OpenAPI AllOf 关系
假设您有一个 SocialUser
OpenAPI 规范,它继承自 User
并具有额外的属性
SocialUser:
allOf:
- $ref: '#components/schema/User'
- type: object
properties:
username:
type: string
isPublic:
type: boolean
在 Swift 代码中,可以使用 AllOfCodable
注解来实现
@AllOfCodable
struct SocialUser {
struct Properties: Codable {
let isPublic: Bool
let username: String
}
let user: User
let additionalProperties: Properties
}
@OneOfCodable
描述了 OpenAPI OneOf 关系
注意 每个枚举案例中只期望有一个关联值
@OneOfCodable
enum PaymentMethod {
case card(DebitCardPayload)
case applePay(payload: ApplePayPayload)
case sepa(_ payload: SepaPayload)
}
// valid jsons:
// { "card": { ... DebitCardPayload ... }
// { "applePay": { ... ApplePayPayload ... } }
// { "sepa": { ... SepaPayload ... } }
使用 @CodingKey(_ key: String)
注解属性,该键将用作解码和编码中的 CodingKey
struct User {
@CodingKey("is_verified")
let isVerified: Bool
}
使用 @OmitCoding()
注解跳过特定属性的编码
struct User {
@OmitCoding()
let isVerified: Bool
}
当您描述一个对象时,其中每个编码属性都是 http 请求体的一部分时,这可能很有用
@Encodable
struct Request {
var endpoint: String { "/user/\(userID)/follow" }
// We don't want to encode userID, since it's not part of the request body
@OmitCoding
let userID: String
let isFollowing: Bool
}
使用 @DefaultValue<Provider: DefaultValueProvider>(_ type: Provider.Type)
在解码失败时提供默认值
警告
@DefaultValue(_:)
不影响编码
@Codable
struct User {
@DefaultValue(BoolFalse) // property will be `false`, if value is absent or decoding fails
let isVerified: Bool
}
内置预设
使用 @ValueStrategy<Strategy: ValueCodableStrategy>(_ strategy: Strategy.Type)
提供自定义映射
@Encodable
struct Upload {
@ValueStrategy(Base64Data)
let document: Data
}
可以与 DefaultValue 结合使用
@Decodable
struct Example {
@ValueStrategy(SomeStringStrategy)
@DefaultValue(EmptyString)
let string: String
}
内置预设
2023-10-03T10:15:30+00:00
2023-10-03
2023-10-03T10:15:30.123+00:00
2023-10-03
Tue, 3 Oct 2023 10:15:30 GMT
2023-10-03T10:15:30Z
String
或 Double
时间戳转换为 Date
,示例:1696291200.0
@CustomCoding
注解允许为属性指定自定义的编码和解码策略。将其附加到属性并指定包含自定义编码/解码逻辑的类型。例如,@CustomCoding(SafeDecoding)
使用来自 CustomCodingDecoding
和 CustomCodingEncoding
的 safeDecoding
函数,以便在编码和解码期间安全地处理数组和字典。
@Codable
struct TaggedPhotos: Equatable {
@CustomCoding(SafeDecoding)
var photos: [Photo]
}
@Codable
struct UserProfiles: Equatable {
@CustomCoding(SafeDecoding)
var profiles: [String: Profile]
}
// Corresponding JSON for TaggedPhotos with corrupted data
// {
// "photos": [
// { "url": "https://example.com/photo1.jpg", "tag": "vacation" },
// { "url": "https://example.com/photo2.jpg", "tag": "family" },
// "corruptedData"
// ]
// }
// Corresponding JSON for UserProfiles with corrupted data
// {
// "profiles": {
// "john_doe": { "age": 25, "location": "NYC" },
// "jane_doe": { "age": 28, "location": "LA" },
// "corrupted_entry": "corruptedData"
// }
// }
在上面的示例中,@CustomCoding(SafeDecoding)
将捕获并将无效解码引起的任何解码错误转发到 CustomCodingDecoding.errorHandler
,从而允许其余数据安全地解码。
struct
swift-foundation 由 Apple Swift Foundation Team 提供,对 Decoder
、Encoder
以及 encodeIfPresent
和 decodeIfPresent
函数的处理有了深刻的理解,这对于像 MacroCodableKit 这样的库是必需的逻辑。
BetterCodable 由 Mark Sands 开发: 这个项目包含了 Codable
的所有常见和广泛的用例,这些用例被 MacroCodableKit 采纳。特别是 键转换案例,事实证明它对于字典上的 SafeDecoding
至关重要