| Xcode | Minimun Deployments | Version |
|---|---|---|
| Xcode15+ | iOS13+ / macOS11+ | 1.0+ |
| Xcode15- | iOS13- / macOS11- | 0.3.3 |
The project objective is to enhance the usage experience of the Codable protocol using the macro provided by Swift 5.9 and to address the shortcomings of various official versions.
- Default value
- Basic type automatic convertible, between
StringBoolNumberetc. - Custom multiple
CodingKey - Nested Dictionary
CodingKey - Automatic compatibility between camel case and snake case
- Convenience
Codablesubclass - Transformer
pod 'CodableWrapper', :git => 'https://github.com/winddpan/CodableWrapper.git'
https://github.com/winddpan/CodableWrapper
@Codable struct BasicModel { var defaultVal: String = "hello world" var defaultVal2: String = Bool.random() ? "hello world" : "" let strict: String let noStrict: String? let autoConvert: Int? @CodingKey("hello") var hi: String = "there" @CodingNestedKey("nested.hi") @CodingTransformer(StringPrefixTransform("HELLO -> ")) var codingKeySupport: String @CodingNestedKey("nested.b") var nestedB: String var testGetter: String { nestedB } } final class CodableWrapperTests: XCTestCase { func testBasicUsage() throws { let jsonStr = """ { "strict": "value of strict", "autoConvert": "998", "nested": { "hi": "nested there", "b": "b value" } } """ let model = try JSONDecoder().decode(BasicModel.self, from: jsonStr.data(using: .utf8)!) XCTAssertEqual(model.defaultVal, "hello world") XCTAssertEqual(model.strict, "value of strict") XCTAssertEqual(model.noStrict, nil) XCTAssertEqual(model.autoConvert, 998) XCTAssertEqual(model.hi, "there") XCTAssertEqual(model.codingKeySupport, "HELLO -> nested there") XCTAssertEqual(model.nestedB, "b value") let encoded = try JSONEncoder().encode(model) let dict = try JSONSerialization.jsonObject(with: encoded) as! [String: Any] XCTAssertEqual(model.defaultVal, dict["defaultVal"] as! String) XCTAssertEqual(model.strict, dict["strict"] as! String) XCTAssertNil(dict["noStrict"]) XCTAssertEqual(model.autoConvert, dict["autoConvert"] as? Int) XCTAssertEqual(model.hi, dict["hello"] as! String) XCTAssertEqual("nested there", (dict["nested"] as! [String: Any])["hi"] as! String) XCTAssertEqual(model.nestedB, (dict["nested"] as! [String: Any])["b"] as! String) } }
-
Auto conformance
Codableprotocol if not explicitly declared// both below works well @Codable struct BasicModel {} @Codable struct BasicModel: Codable {}
-
Default value
@Codable struct TestModel { let name: String var balance: Double = 0 } // { "name": "jhon" }
-
Basic type automatic convertible, between
StringBoolNumberetc.@Codable struct TestModel { let autoConvert: Int? } // { "autoConvert": "998" }
-
Automatic compatibility between camel case and snake case
@Codable struct TestModel { var userName: String = "" } // { "user_name": "jhon" }
-
Member Wise Init
@Codable public struct TestModel { public var userName: String = "" // Automatic generated public init(userName: String = "") { self.userName = userName } }
@Codable(wiseInit: false) public struct TestModel { public var userName: String = "" // Disable WiseInit Automatic generated }
-
Custom
CodingKeys@Codable struct TestModel { @CodingKey("u1", "u2", "u9") var userName: String = "" } // { "u9": "jhon" }
-
Ignored propery on encode and decode
struct NonCodable {} @Codable struct TestModel { @CodingKeyIgnored var nonCodable: NonCodable? }
-
Custom
CodingKeys innested dictionary@Codable struct TestModel { @CodingNestedKey("data.u1", "data.u2", "data.u9") var userName: String = "" } // { "data": {"u9": "jhon"} }
-
Automatic generate
Codableclass's subclassinit(from:)andencode(to:)super calls@Codable class BaseModel { let userName: String } @CodableSubclass class SubModel: BaseModel { let age: Int } // {"user_name": "jhon", "age": 22}
-
Transformer between in
Codable/NonCodablemodelstruct DateWrapper { let timestamp: TimeInterval var date: Date { Date(timeIntervalSince1970: timestamp) } init(timestamp: TimeInterval) { self.timestamp = timestamp } static var transformer = TransformOf<DateWrapper, TimeInterval>(fromJSON: { DateWrapper(timestamp: 0ドル ?? 0) }, toJSON: { 0ドル.timestamp }) } @Codable struct DateModel { @CodingTransformer(DateWrapper.transformer) var time: DateWrapper? = DateWrapper(timestamp: 0) @CodingTransformer(DateWrapper.transformer) var time1: DateWrapper = DateWrapper(timestamp: 0) @CodingTransformer(DateWrapper.transformer) var time2: DateWrapper? } class TransformTest: XCTestCase { func testDateModel() throws { let json = """ {"time": 12345} """ let model = try JSONDecoder().decode(DateModel.self, from: json.data(using: .utf8)!) XCTAssertEqual(model.time?.timestamp, 12345) XCTAssertEqual(model.time?.date.description, "1970年01月01日 03:25:45 +0000") let encode = try JSONEncoder().encode(model) let jsonObject = try JSONSerialization.jsonObject(with: encode, options: []) as! [String: Any] XCTAssertEqual(jsonObject["time"] as! TimeInterval, 12345) } }