Xcode | 最低部署版本 | 版本 |
---|---|---|
Xcode15+ | iOS13+ / macOS11+ | 1.0+ |
< Xcode15 | < iOS13 / macOS11 | 0.3.3 |
该项目旨在通过 Swift 5.9 提供的宏来增强 Codable 协议的使用体验,并解决各种官方版本的缺点。
String
Bool
Number
等。CodingKey
CodingKey
Codable
子类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)
}
}
自动遵循 Codable
协议(如果未显式声明)
// both below works well
@Codable
struct BasicModel {}
@Codable
struct BasicModel: Codable {}
默认值
@Codable
struct TestModel {
let name: String
var balance: Double = 0
}
// { "name": "jhon" }
基本类型自动转换,例如 String
Bool
Number
等。
@Codable
struct TestModel {
let autoConvert: Int?
}
// { "autoConvert": "998" }
自动兼容驼峰命名和蛇形命名
@Codable
struct TestModel {
var userName: String = ""
}
// { "user_name": "jhon" }
逐成员初始化器
@Codable
public struct TestModel {
public var userName: String = ""
// Automatic generated
public init(userName: String = "") {
self.userName = userName
}
}
自定义 CodingKey
@Codable
struct TestModel {
@CodingKey("u1", "u2", "u9")
var userName: String = ""
}
// { "u9": "jhon" }
在 nested dictionary
中的自定义 CodingKey
@Codable
struct TestModel {
@CodingNestedKey("data.u1", "data.u2", "data.u9")
var userName: String = ""
}
// { "data": {"u9": "jhon"} }
自动生成 Codable
类的子类的 init(from:)
和 encode(to:)
超类调用
@Codable
class BaseModel {
let userName: String
}
@CodableSubclass
class SubModel: BaseModel {
let age: Int
}
// {"user_name": "jhon", "age": 22}
Codable
/ NonCodable
模型之间的转换器
struct 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)
}
}