CodableWrapper 0.3.3

CodableWrapper 0.3.3

winddpan 维护。



  • winddpan 和 scyano

CodableWrapper

Codable + PropertyWrapper = @Codec("encoder", "decoder") var cool: Bool = true

  1. 关于
  2. 特性
  3. 安装
  4. 示例
  5. 工作原理
  6. 用法

中文说明

关于

  • 该项目使用 PropertyWrapper 来提升您的 Codable 使用体验。
  • 简单基于 JSONEncoderJSONDecoder
  • 功能强大、API 简化的 API,比 BetterCodableCodableWrappers 更好。

特性

  • 支持默认值
  • 基本类型可转换,在 String Bool Number 之间
  • 支持自定义键
  • 修复因缺少字段导致的解析失败
  • 修复因原始值不匹配导致的枚举解析失败
  • 自定义转换

安装

Cocoapods

pod 'CodableWrapper'

Swift Package Manager

https://github.com/winddpan/CodableWrapper

示例

enum Animal: String, Codable {
    case dog
    case cat
    case fish
}

struct ExampleModel: Codable {
    @Codec("aString")
    var stringVal: String = "scyano"

    @Codec("aInt")
    var intVal: Int = 123456

    @Codec var defaultArray: [Double] = [1.998, 2.998, 3.998]

    @Codec var bool: Bool = false

    @Codec var unImpl: String?
    
    @Codec var animal: Animal = .dog
}

let json = #"{"aString": "pan", "aInt": "233", "bool": "1", "animal": "cat"}"#

let model = try JSONDecoder().decode(ExampleModel.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.stringVal, "pan")
XCTAssertEqual(model.intVal, 233)
XCTAssertEqual(model.defaultArray, [1.998, 2.998, 3.998])
XCTAssertEqual(model.bool, true)
XCTAssertEqual(model.unImpl, nil)
XCTAssertEqual(model.animal, .cat)

更多示例,请查看单元测试或Playground

工作原理

struct DataModel: Codable {
    @Codec var stringVal: String = "OK"
}

/* pseudocode from Swift open source lib: Codable.Swift -> */
struct DataModel: Codable {
    private var _stringVal = Codec<String>(defaultValue: "OK")

    var stringVal: String {
        get {
            return _stringVal.wrappedValue
        }
        set {
            _stringVal.wrappedValue = newValue
        }
    }

    enum CodingKeys: CodingKey {
        case stringVal
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        /* decode `newStringVal` */
        /* remember `newStringVal`: Thread.current.lastCodableWrapper = wrapper */
        /*
         extension KeyedDecodingContainer {
            func decode<Value>(_ type: Codec<Value>.Type, forKey key: Key) throws -> Codec<Value> {
                ...
                let wrapper = Codec<Value>(unsafed: ())
                Thread.current.lastCodableWrapper = wrapper
                ...
            }
         }
         */
        let newStringVal = try container.decode(Codec<String>.self, forKey: CodingKeys.stringVal)

        /* old `_stringVal` deinit */
        /* old `_stringVal` invokeAfterInjection called: transform old `_stringVal` Configs to `newStringVal` */
        /* 
         deinit {
             if !unsafeCreated, let construct = construct, let lastWrapper = Thread.current.lastCodableWrapper as? Codec<Value> {
                 lastWrapper.invokeAfterInjection(with: construct)
                 Thread.current.lastCodableWrapper = nil
             }
         }
        */
        self._stringVal = newStringVal
    }
}

用法

默认值

默认值应实现 Codable 协议

struct ExampleModel: Codable {
    @Codec var bool: Bool = false
}

let json = #"{"bool":"wrong value"}"#

let model = try JSONDecoder().decode(ExampleModel.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.bool, false)

自动 snake 到 camel 转换

struct ExampleModel: Codable {
    @Codec var snake_string: String = ""
    @Codec var camelString: String = ""
}

let json = #"{"snakeString":"snake", "camel_string": "camel"}"#

let model = try JSONDecoder().decode(ExampleModel.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.snake_string, "snake")
XCTAssertEqual(model.camelString, "camel")

编码键

解码:尝试每个编码键直到成功 编码:使用第一个编码键作为字典键

struct ExampleModel: Codable {
    @Codec("int_Val", "intVal")
    var intVal: Int = 123456

    @Codec("intOptional", "int_optional")
    var intOptional: Int?
}

let json = #"{"int_Val": "233", "int_optional": 234}"#

let model = try JSONDecoder().decode(ExampleModel.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.intVal, 233)
XCTAssertEqual(model.intOptional, 234)

let data = try JSONEncoder().encode(model)
let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
XCTAssertEqual(jsonObject["int_Val"] as? Int, 233)
XCTAssertEqual(jsonObject["intOptional"] as? Int, 234)

基本类型桥接

struct ExampleModel: Codable {
    @Codec var int: Int?
    @Codec var string: String?
    @Codec var bool: Bool?
}

let json = #"{"int": "1", "string": 2, "bool": "true"}"#

let model = try JSONDecoder().decode(ExampleModel.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.int, 1)
XCTAssertEqual(model.string, "2")
XCTAssertEqual(model.bool, true)

变换器

struct User: Codable {
    @Codec(transformer: SecondDateTransform())
    var registerDate: Date?
}       
let date = Date()
let json = #"{"sencondsDate": \(date.timeIntervalSince1970)}"#

let user = try JSONDecoder().decode(User.self, from: json.data(using: .utf8)!)
XCTAssertEqual(model.sencondsDate?.timeIntervalSince1970, date.timeIntervalSince1970)

同时也支持自定义变换器,您的CustomTransformer只需要确认TransformType

许可

遵循MIT许可证发布。更多信息请参阅LICENSE