我正在处理一个需要修改我们的iOS模型结构的请求,修改是将
EncodingOption
参数从EditingOptions
结构移动到OutputOptions
类。
配置的层次结构
AppConfig {
profile: ProfileSetting
}
ProfileSetting {
editSetting:EditingOptions
outputSetting: OutputOptions
}
以前的数据结构:
class EditingOptions: NSObject, Codable {
//..other parameters
}
struct OutputOptions: Codable {
var barcodeEncoding: EncodingOption = .utf8
//..other parameters
}
修改后的数据结构:
class EditSetting: NSObject, Codable {
var encodingOption: EncodingOption
//..other parameters
}
struct OutputSetting: Codable {
//..other parameters
}
修改后的结构与之前的配置文件不兼容,出现 JSON 错误
keyNotFound
:
keyNotFound(CodingKeys(stringValue: "encodingOption", intValue: nil),
Swift.DecodingError.Context(codingPath: [
CodingKeys(stringValue: "profileManage", intValue: nil), CodingKeys(stringValue: "deviceName",
intValue: nil), CodingKeys(stringValue: "profiles", intValue: nil),
_JSONKey(stringValue: "Index 0", intValue: 0),
CodingKeys(stringValue: "outputOptions", intValue: nil)
],
debugDescription: "No value associated with key CodingKeys(stringValue: \"encodingOption\", intValue: nil) (\"encodingOption\").", underlyingError: nil))
ChatGPT 的解决方案是为
init(from decoder: Decoder)
类添加 ProfileSetting
方法:
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
//...other parameters
if let editingOptions = try? container.decode(EditingOptions.self, forKey: .editingOptions) {
self.editingOptions = editingOptions
} else {
self.editingOptions = EditingOptions()
}
}
barcodeEncoding
是一个默认设置的隐藏参数,尚未公开发布。
该解决方案确实解决了
keyNotFound
错误,但是,我不确定该解决方案是否是解决问题的 RIGHT 方法。
如果我理解正确,你的问题可以简化为:
let json = """
{
"a": { "keyA": "Value for KeyA" },
"b": { "keyB": "Value for KeyB",
"otherKey": "My value To Pass to a now "}
}
"""
其中
otherKey
是你的 encodingOption
。它存在于 B
上,但现在您希望它将它传递给 A
。
所以旧代码是:
func oldCode(with json: String) {
struct OldParent: Codable {
let a: OldA
let b: OldB
}
class OldA: NSObject, Codable {
let keyA: String
}
struct OldB: Codable {
let keyB: String
let otherKey: String
}
let decoder = JSONDecoder()
do {
let parent = try decoder.decode(OldParent.self, from: Data(json.utf8))
print(parent)
print("--")
} catch {
print("Error: \(error)")
}
}
它按设计工作,您的 iOS 模型反映了 API 模型。
现在你想修改你的iOS模型,但是API不会改变。
一个可能的解决方案是将
otherKey
保留在 B
中,并在 Parent
的解码中(它知道 A
和 B
),将该值传递给 A
:
func newCode(with json: String) {
struct NewParent: Codable {
let a: NewA
let b: NewB
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.a = try container.decode(NewA.self, forKey: .a)
self.b = try container.decode(NewB.self, forKey: .b)
self.a.otherKey = self.b.otherKey //Pass the value
}
}
class NewA: NSObject, Codable {
let keyA: String
var otherKey: String = "defaultValue"
enum CodingKeys: CodingKey {
case keyA //We skip here otherKey to tell the decoder to decode only keyA which is present in the JSON
}
}
struct NewB: Codable {
let keyB: String
let otherKey: String //Only because it's in JSON
}
let decoder = JSONDecoder()
do {
let parent = try decoder.decode(NewParent.self, from: Data(json.utf8))
print(parent)
print("--")
} catch {
print("Error: \(error)")
}
}