struct AStudent: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.aID = try container.decode(String.self, forKey: .aID)
self.aName = try container.decode(String.self, forKey: .aName)
let gradeDecoded = try container.decode(Double.self, forKey: .aGrade)
self.AGrede = Int(gradeDecoded)
}
enum CodingKeys: String, CodingKey {
case aName = "name"
case aGrade = "grade"
case aID = "id"
}
var aID: String
var aName: String
var AGrede: Int
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(aID, forKey: .aID)
try container.encode(Double(AGrede), forKey: .aGrade)
try container.encode(aName, forKey: .aName)
}
}
struct Student: SuperCodable {
@Keyed
var id: String
@Keyed("name")
var aName: String
@KeyedTransform("grade", doubleTransform)
var AGrade: Int
}
let doubleTransform = SCTransformOf<Int, Double> {
(double) -> Int in
Int(double)
} toEncoder: { (int) -> Double in
Double(int)
}
struct AnyValueJSON: SuperCodable {
@KeyedTransform(IDTransform)
var id:Int
}
let data =
#"""
[
{
"id": "0",
},
{
"id": 1,
},
{
"id": "abc",
},
{
"id": true,
},
]
"""#.data(using: .utf8)!
let sut = try! JSONDecoder().decode([AnyValueJSON].self, from: data)
XCTAssertEqual(sut.count, 4)
XCTAssertEqual(sut.map(\.id), [0, 1, 0, 1])
可以在 Tests/SuperCodableTests/AnyValueDecode.swift 中找到
Foundation.Codable
属性init()
@Keyed var id:Int
将对底层包装器 _VARIABLE_NAME
进行 O(n) 计算 以得到键 VARIABLE_NAME
。 请注意变量名过长会耗时过久DecodableKey
/ EncodableKey
,否则该属性(应该是 Codable
)将在 Codable 过程中被简单地忽略。为什么
基本上,反射无法在
init(from decoder:) throws
期间修改对象值,因为我们从self.init()
创建对象
灵感来自: https://medium.com/trueid-developers/combined-propertywrapper-with-codable-swift-368dc4aa2703
尝试将 @KeyedTransform
合并到 @Keyed
中,但它要求 @Keyed var id: String
必须是 @Keyed() var id: String
,带有额外的 ()
🧐
Swift 应该为您自动生成 STRUCT.init(...)
,但是如果您使用没有默认值的 @Keyed var id: String
,它将生成 init(id: Keyed<String>)
,通过提供默认值 @Keyed var id: String = ""
应该可以解决这个问题。
@Keyed var id:String?
将在强制解包 Keyed.value?
时导致 fatalError 错误,您可以使用 @OptionalKeyed
来使其工作。OptionalKeyed
可能/可能不是一个好名字,我正在考虑使其易于更改,也许 KeyedOptional
更容易更改? 🤔