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
String
Bool
Number
etc. - Custom multiple
CodingKey
- Nested Dictionary
CodingKey
- Automatic compatibility between camel case and snake case
- Convenience
Codable
subclass - 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
Codable
protocol 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
String
Bool
Number
etc.@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 } }
-
Custom
CodingKey
s@Codable struct TestModel { @CodingKey("u1", "u2", "u9") var userName: String = "" } // { "u9": "jhon" }
-
Custom
CodingKey
s innested dictionary
@Codable struct TestModel { @CodingNestedKey("data.u1", "data.u2", "data.u9") var userName: String = "" } // { "data": {"u9": "jhon"} }
-
Automatic generate
Codable
class'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
/NonCodable
modelstruct 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) } }