Project Icon

CodableWrappers

Swift序列化的声明式解决方案

CodableWrappers是一个Swift库,通过声明式注解简化Codable序列化过程。该库提供了丰富的属性包装器和宏,用于自定义编码键、处理特殊值和转换日期格式。支持Swift Package Manager和CocoaPods,适用于iOS、macOS等平台。CodableWrappers为开发者提供了高效处理JSON等数据格式序列化的工具,大大简化了相关编码工作。

CodableWrappers

使用属性包装器简化序列化

通过声明式注解轻松实现复杂的Codable序列化!

@CustomCodable @SnakeCase
struct User: Codable {
    let firstName: String
    let lastName: String
    @SecondsSince1970DateCoding
    var joinDate: Date
    @CustomCodingKey("data")
    var imageData: Data
}

3.0版本已发布!发布说明


文档

感谢Swift Package Index提供的完整DocC文档

安装

Swift Package Manager 推荐

URL:

https://github.com/GottaGetSwifty/CodableWrappers.git

清单:

dependencies: [
    .package(url: "https://github.com/GottaGetSwifty/CodableWrappers.git", .upToNextMajor(from: "3.0.0" )),
]

CocoaPods

pod 'CodableWrappers', '~> 3.0.0'

可用的CodingKey宏

可用的属性包装器

其他自定义

其他链接


@CustomCodable

自定义CodingKeys的前提条件

@Codable
struct MyType: Codable {
}

@CustomCodingKey(String)

为属性的CodingKey使用自定义字符串值

@CustomCodable
struct YourType: Codable {
    @CodingKey("your-Custom_naming")
    let firstProperty: String // 编码键将为 "your-Custom_naming"
}

CodingKeyPrefix(String)

使用自定义值设置属性的CodingKey前缀

@CustomCodable
struct YourType: Codable {
    @CodingKeyPrefix("beta-")
    let firstProperty: String // CodingKey将为 "beta-firstProperty"
}
@CustomCodable @CodingKeyPrefix("beta-")
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "beta-firstProperty"
}

CodingKeySuffix(String)

为属性的CodingKey或类型的CodingKeys添加自定义后缀

@CustomCodable
struct YourType: Codable {
    @CodingKeySuffix("-beta")
    let firstProperty: String // CodingKey将为 "firstProperty-beta"
}
@CustomCodable @CodingKeySuffix("-beta")
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "firstProperty-beta"
}

CamelCase

将属性或类型的CodingKey设为camelCase

@CustomCodable
struct YourType: Codable {
    @CamelCase
    let first-property: String // CodingKey将为 "firstProperty"
}
@CustomCodable @CamelCase
struct YourType: Codable {
    let first-property: String // CodingKey将为 "firstProperty"
}

@FlatCase

将属性或类型的CodingKey设为flatcase

@CustomCodable
struct YourType: Codable {
    @FlatCase
    let firstProperty: String // CodingKey将为 "firstproperty"
}
@CustomCodable @FlatCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "firstproperty"
}

@PascalCase

将属性或类型的CodingKey设为PascalCase

@CustomCodable
struct YourType: Codable {
    @PascalCase
    let firstProperty: String // CodingKey将为 "FirstProperty"
}
@CustomCodable @PascalCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "FirstProperty"
}

@UpperCase

将属性或类型的CodingKey设为UPPERCASE

@CustomCodable
struct YourType: Codable {
    @UpperCase
    let firstProperty: String // CodingKey将为 "FIRSTPROPERTY"
}
@CustomCodable @UpperCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "FIRSTPROPERTY"
}

@SnakeCase

将属性或类型的CodingKey设为snake_case

@CustomCodable
struct YourType: Codable {
    @SnakeCase
    let firstProperty: String // CodingKey将为 "first_property"
}
@CustomCodable @SnakeCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey将为 "first_property"
}

@CamelSnakeCase

将属性或类型的CodingKey设为camel_Snake_Case

@CustomCodable
struct YourType: Codable {
    @CamelSnakeCase
    let firstProperty: String // CodingKey 将会是 "first_Property"
}
@CustomCodable @CamelSnakeCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "first_Property"
}

@PascalSnakeCase

将属性或类型的 CodingKey 设为 Pascal_Snake_Case

@CustomCodable
struct YourType: Codable {
    @PascalSnakeCase
    let firstProperty: String // CodingKey 将会是 "First_Property"
}
@CustomCodable @PascalSnakeCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "First_Property"
}

@ScreamingSnakeCase

将属性或类型的 CodingKey 设为 SCREAMING_SNAKE_CASE

@CustomCodable
struct YourType: Codable {
    @ScreamingSnakeCase
    let firstProperty: String // CodingKey 将会是 "FIRST_PROPERTY"
}
@CustomCodable @ScreamingSnakeCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "FIRST_PROPERTY"
}

@KebabCase

将属性或类型的 CodingKey 设为 kebab-case

@CustomCodable
struct YourType: Codable {
    @KebabCase
    let firstProperty: String // CodingKey 将会是 "first-property"
}
@CustomCodable @KebabCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "first-property"
}

@CamelKebabCase

将属性或类型的 CodingKey 设为 camel-Kebab-Case

@CustomCodable
struct YourType: Codable {
    @CamelKebabCase
    let firstProperty: String // CodingKey 将会是 "first-Property"
}
@CustomCodable @CamelKebabCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "first-Property"
}

@PascalKebabCase

将属性或类型的 CodingKey 设为 Pascal-Kebab-Case

@CustomCodable
struct YourType: Codable {
    @PascalKebabCase
    let firstProperty: String // CodingKey 将会是 "First-Property"
}
@CustomCodable @PascalKebabCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "First-Property"
}

@ScreamingKebabCase

将属性或类型的 CodingKey 设为 SCREAMING-KEBAB-CASE

@CustomCodable
struct YourType: Codable {
    @ScreamingKebabCase
    let firstProperty: String // CodingKey 将会是 "FIRST-PROPERTY"
}
@CustomCodable @ScreamingKebabCase 
struct YourType: Codable {
    let firstProperty: String // CodingKey 将会是 "FIRST-PROPERTY"
}

@EncodeNulls

用于应该为 nil 值编码 null 的属性

struct MyType: Codable {
    @EncodeNulls
    var myText: String? // 当为nil时不会被省略,例如在JSON中会编码为`null`,在PLIST中会编码为`$null`
}

有损集合

@LossyArrayDecoding
@LossyDictionaryDecoding
@LossySetDecoding

在解码过程中过滤掉空值而不抛出错误

private struct LossyCollectionModel: Codable, Equatable {
    @LossyArrayDecoding
    var array: [String] // 忽略空值而不抛出错误
    @LossyDictionaryDecoding
    var dictionary: [String:String] // 忽略空值而不抛出错误
    @LossySetDecoding
    var set: Set<String> // 忽略空值而不抛出错误
}

空值默认

当你想要编码/解码一个空值而不是解码为nil或省略编码时

struct MyType: Codable {
    @FallbackEncoding<EmptyInt>
    var int: Int? // 当为nil时会编码为`0`
    @FallbackDecoding<EmptyString>
    var string: String // 当值缺失/为nil时会解码为""
    @FallbackCoding<EmptyArray>
    var array: [Int]? // 当缺失/为nil时会编码/解码为[]
}
所有空值
BoolTrue
BoolFalse
EmptyBool
EmptyString
EmptyInt
EmptyInt16
EmptyInt32
EmptyInt64
EmptyInt8
EmptyUInt
EmptyUInt16
EmptyUInt32
EmptyUInt64
EmptyUInt8
EmptyCGFloat
EmptyDouble
EmptyFloat
EmptyFloat16
EmptyArray
EmptyDictionary
EmptySet

Empty 默认值可用于大多数典型的Foundation类型

其他回退值

任何其他类型的默认值可以通过自定义 FallbackValueProvider 提供

public struct DistantFutureDateProvider: FallbackValueProvider {
    public static var defaultValue: Date { Date.distantFuture }
}

struct MyType: Codable {
    @FallbackEncoding<DistantFutureDateProvider>
    var updatedDate: Date?
}

@OmitCoding

用于你想在(编/解)码时忽略的属性

struct MyType: Codable {
    @OmitCoding
    var myText: String? // 永远不会编码,并且在解码数据中存在值时会忽略它
}

@Base64Coding

用于应该序列化为Base64编码字符串的Data属性

struct MyType: Codable {
    @Base64Coding
    var myData: Data // 现在会编码为Base64字符串
}

@SecondsSince1970DateCoding

用于应该序列化为1970年以来秒数的Date属性

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var myDate: Date // 现在会编码为1970年以来的秒数
}

@MillisecondsSince1970DateCoding

用于应该序列化为1970年以来毫秒数的Date属性

struct MyType: Codable {
    @MillisecondsSince1970DateCoding
    var myDate: Date // 现在会编码为1970年以来的毫秒数
}

@DateFormatterCoding<DateFormatterStaticCoder>

对于其他日期格式,创建一个遵循 DateFormatterStaticCoder 协议的类型,并使用便利的 @DateFormatterCoding 类型别名或 @CodingUses<StaticCoder>

struct MyCustomDateCoder: DateFormatterStaticCoder {
    static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "MM:dd:yy H:mm:ss"
        return formatter
    }()
}

struct MyType: Codable {
    @DateFormatterCoding<MyCustomDateCoder>
    var myDate: Date // 现在会编码为格式:"MM:dd:yy H:mm:ss"
}

@ISO8601DateCoding

用于应该使用ISO8601DateFormatter序列化的Date属性

struct MyType: Codable {
    @ISO8601DateCoding
    var myDate: Date // 现在会编码为ISO8601格式
}

@ISO8601DateFormatterCoding<ISO8601DateFormatterStaticCoder>

对于其他日期格式,创建一个遵循 ISO8601DateFormatterStaticCoder 协议的类型,并使用便利的 @ISO8601DateFormatterCoding 类型别名或 @CodingUses<StaticCoder>

@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
struct MyCustomISO8601DateFormatter: ISO8601DateFormatterStaticCoder {
    static let iso8601DateFormatter: ISO8601DateFormatter = {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate]
        return formatter
    }()
}


struct MyType: Codable {
    @ISO8601DateFormatterCoding<MyCustomISO8601DateFormatter>
    var myDate: Date // 现在会使用MyCustomISO8601DateFormatter的格式化器进行编码
}

@NonConformingFloatCoding<ValueProvider>

当使用非标准的Float时,创建一个遵循NonConformingDecimalValueProvider的类型,并使用 @NonConformingFloatCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingFloatCoding<MyNonConformingValueProvider>
    var myFloat: Float // 现在会使用MyNonConformingValueProvider的值来编码无穷大/NaN
}

@NonConformingDoubleCoding<ValueProvider>

当使用非标准的Double类型时,创建一个遵循NonConformingDecimalValueProvider协议的类型,并使用@NonConformingDoubleCoding<NonConformingDecimalValueProvider>

struct MyNonConformingValueProvider: NonConformingDecimalValueProvider {
    static var positiveInfinity: String = "100"
    static var negativeInfinity: String = "-100"
    static var nan: String = "-1"
}

struct MyType: Codable {
    @NonConformingDoubleCoding<MyNonConformingValueProvider>
    var myFloat: Float // 现在使用MyNonConformingValueProvider的值来编码无穷大/NaN
}

布尔值编码

有时API会使用IntString来表示布尔值。

@BoolAsStringCoding

struct MyType: Codable {
    @BoolAsStringCoding
    var myBool: Bool // 现在以字符串形式编码/解码。`true`编码为`"true"`,`false`编码为`"false"`。(解码前值会转为小写)
}

@BoolAsIntCoding

struct MyType: Codable {
    @BoolAsIntCoding
    var myBool: Bool // 现在以整数形式编码/解码。`true`编码为`1`,`false`编码为`0`。
}

额外自定义

该架构在设计时考虑了可扩展性,实现自定义编码只需遵循StaticCoder协议即可。然后只需在属性上添加@CodingUses<YourCustomCoder>,或创建一个类型别名使其更简洁:typealias YourCustomCoding = CodingUses<YourCustomCoder>

事实上,所有包含的包装器都是以相同方式构建的!

完整示例


struct NanosecondsSince9170Coder: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Date {
        let nanoSeconds = try Double(from: decoder)
        let seconds = nanoSeconds * 0.000000001
        return Date(secondsSince1970: seconds)
    }

    static func encode(value: Date, to encoder: Encoder) throws {
        let nanoSeconds = value.secondsSince1970 / 0.000000001
        return try nanoSeconds.encode(to: encoder)
    }
}

// 方法1:CustomCoding
struct MyType: Codable {
    @CodingUses<NanosecondsSince9170Coder>
    var myData: Date // 现在使用NanosecondsSince9170Coder进行序列化
}

// 方法2:CustomEncoding属性包装器类型别名

typealias NanosecondsSince9170Coding = CodingUses<NanosecondsSince9170Coder>

struct MyType: Codable {
    @NanosecondsSince9170Coding
    var myData: Date // 现在使用NanosecondsSince9170Coder进行序列化
}

查看这些其他示例以了解更多可能性。


属性可变性

在2.0版本中,所有包装器默认都是可变的,可以通过属性包装器组合使其不可变

struct MyType: Codable {
    @Immutable @SecondsSince1970DateCoding
    var createdAt: Date

    @SecondsSince1970DateCoding
    var updatedAt: Date

    mutating func update() {
        createdAt = Date() // 错误 - 无法赋值给属性:'createdAt'是只读属性
        updatedAt = Date() // 正常工作!
    }
}

可选类型

2.0版本引入了@OptionalCoding<StaticCodingWrapper>来支持属性的可选类型。

struct MyType: Codable {
    @SecondsSince1970DateCoding
    var createdAt: Date

    @OptionalCoding<SecondsSince1970DateCoding>
    var updatedAt: Date?
}

仅编码或解码

有时你可能只想或只能实现编码或解码。

为了支持这一点,(在实际可行的情况下)所有包含的包装器都有编码和解码变体

将Coder改为Encoder/Decoder或将Coding改为Encoding/Decoding以仅实现其中一个 例如:@Base64Encoding@SecondsSince1970DateDecoding@EncodingUses<ACustomEncoder>等。

struct MyType: Encodable {
    @SecondsSince1970DateEncoding
    var myDate: Date
}

struct MyType: Decodable {
    @SecondsSince1970DateDecoding
    var myDate: Date
}


兼容性

  • 3.x支持Swift 5.9
  • 2.x支持Swift 5.2
  • 1.x支持Swift 5.1

贡献

如果有标准的序列化或编码键策略可以添加,欢迎开启一个问题请求或提交包含新选项的拉取请求。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号