采用与@Code Different's answer 类似的方法,您可以通过解码器的userInfo 字典传递给定的参数信息,然后将其传递给您用于从密钥容器中解码的密钥类型。
首先,我们可以在CodingUserInfoKey 上定义一个新的静态成员,用作userInfo 字典中的键:
extension CodingUserInfoKey {
static let endPointParameter = CodingUserInfoKey(
rawValue: "com.yourapp.endPointParameter"
)!
}
(强制解包永远不会失败;我认为初始化程序是失败的as a bug)。
然后我们可以为您的端点参数定义一个类型,再次使用静态成员来抽象出底层字符串:
// You'll probably want to rename this to something more appropriate for your use case
// (same for the .endPointParameter CodingUserInfoKey).
struct EndpointParameter {
static let xxx = EndpointParameter("XXX")
static let yyy = EndpointParameter("YYY")
// ...
var stringValue: String
init(_ stringValue: String) { self.stringValue = stringValue }
}
然后我们可以定义你的数据模型类型:
struct MyDataModel {
var fixedKey1: String
var fixedKey2: String
var variableKey1: String
var variableKey2: String
}
然后像这样Decodable:
extension MyDataModel : Decodable {
private struct CodingKeys : CodingKey {
static let fixedKey1 = CodingKeys("fixed_key1")
static let fixedKey2 = CodingKeys("fixed_key2")
static func variableKey1(_ param: EndpointParameter) -> CodingKeys {
return CodingKeys("variable_key_1_\(param.stringValue)")
}
static func variableKey2(_ param: EndpointParameter) -> CodingKeys {
return CodingKeys("variable_key_2_\(param.stringValue)")
}
// We're decoding an object, so only accept String keys.
var stringValue: String
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
init(stringValue: String) { self.stringValue = stringValue }
init(_ stringValue: String) { self.stringValue = stringValue }
}
init(from decoder: Decoder) throws {
guard let param = decoder.userInfo[.endPointParameter] as? EndpointParameter else {
// Feel free to make this a more detailed error.
struct EndpointParameterNotSetError : Error {}
throw EndpointParameterNotSetError()
}
let container = try decoder.container(keyedBy: CodingKeys.self)
self.fixedKey1 = try container.decode(String.self, forKey: .fixedKey1)
self.fixedKey2 = try container.decode(String.self, forKey: .fixedKey2)
self.variableKey1 = try container.decode(String.self, forKey: .variableKey1(param))
self.variableKey2 = try container.decode(String.self, forKey: .variableKey2(param))
}
}
您可以看到我们在CodingKeys 上使用静态属性定义固定键,而对于可变键,我们使用将给定参数作为参数的静态方法。
现在您可以像这样执行解码:
let jsonString = """
[
{
"fixed_key1": "value1",
"fixed_key2": "value2",
"variable_key_1_XXX": "some value",
"variable_key_2_XXX": "some other value"
}
]
"""
let decoder = JSONDecoder()
decoder.userInfo[.endPointParameter] = EndpointParameter.xxx
do {
let model = try decoder.decode([MyDataModel].self, from: Data(jsonString.utf8))
print(model)
} catch {
print(error)
}
// [MyDataModel(fixedKey1: "foo", fixedKey2: "bar",
// variableKey1: "baz", variableKey2: "qux")]