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', '0.3.3'
No longer supported since 1.0.0, use version 0.3.3 if your project uses <Xcode 15 or <iOS 13.
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
andCodableObversable
protocol if not explicitly declared// both below works well @Codable struct BasicModel {} @Codable struct BasicModel: Codable {} @Codable struct BasicModel: Codable, CodableObversable {} @Codable struct BasicModel { var age: Int = 0 mutating func didDecodeFinish() { age = 1 } }
-
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"} }
-
Custom
Coding
ignore in Model@Codable struct TestModel { @CodingIgnoreKey var userName: String = "" } // { "userName": "jhon" } // result: userName is nil
-
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) } }
-
Swift Package will be build automatically when you first
pod install
, the first build need a few time. -
This means that when there is a
relase
shortcut in the directoryCodableWrapper/.build
, the Package builds successfully. -
There is a situation that
pod install
will build automatically, if the Package auto build is not completed, the build will fail when you build the project.script = <<-SCRIPT env -i PATH="$PATH" "$SHELL" -l -c "swift build -c release --package-path \\"$PODS_TARGET_SRCROOT\\" --build-path \\"${PODS_BUILD_DIR}/CodableWrapper\\"" SCRIPT
-
The first important setting, it's used to set the SwiftMacros plugin path for the main project.
-
You need to replace this with your custom path
post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -Xfrontend -load-plugin-executable -Xfrontend $(PODS_BUILD_DIR)/CodableWrapper/release/CodableWrapperMacros#CodableWrapperMacros' end end end
-
The second important setting, both of them are used to set the SwiftMacros plugin path for the Development Pods in the Pod project.
-
You need to replace them with your custom path
s.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-Xfrontend -load-plugin-executable -Xfrontend $(PODS_BUILD_DIR)/CodableWrapper/release/CodableWrapperMacros#CodableWrapperMacros" } s.user_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-Xfrontend -load-plugin-executable -Xfrontend $(PODS_BUILD_DIR)/CodableWrapper/release/CodableWrapperMacros#CodableWrapperMacros" }