Sin*_*hus 5 struct decoding swift codable identifiable
在嵌套Codable结构中使用解码器时,有没有办法访问父结构的属性?
我能想到的唯一方法(尚未测试)是在父结构中也使用手动解码器,在userInfo字典中设置属性,然后userInfo在子结构中访问。但这会导致大量样板代码。我希望有一个更简单的解决方案。
struct Item: Decodable, Identifiable {
let id: String
let title: String
let images: Images
struct Images: Decodable {
struct Image: Decodable, Identifiable {
let id: String
let width: Int
let height: Int
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
width = try container.decode(Int.self, forKey: .width)
height = try container.decode(Int.self, forKey: .height)
// How do I get `parent.parent.id` (`Item#id`) here?
id = "\(parent.parent.id)\(width)\(height)"
}
}
let original: Image
let small: Image
// …
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,来自服务器的项目 ID 仅在 JSON 的顶级属性中定义,但我也需要在子项中使用它们,因此我也可以使它们Identifiable.
我使用 @New Dev 提到的 Itai Ferber 的建议进行了管理,方法如下:
\n我已将您上面的示例修改如下:
\nstruct Item: Decodable, Identifiable {\n\n enum CodingKeys: String, CodingKey {\n case id\n case title\n case images\n }\n\n let id: String\n let title: String\n let images: Images\n\n struct Images: Decodable {\n struct Image: Decodable, Identifiable {\n let id: String\n let width: Int\n let height: Int\n\n init(from decoder: Decoder) throws {\n let container = try decoder.container(keyedBy: CodingKeys.self)\n width = try container.decode(Int.self, forKey: .width)\n height = try container.decode(Int.self, forKey: .height)\n\n if let referenceTypeUsedOnlyToContainAChangeableIdentifier = decoder.userInfo[.referenceTypeUsedOnlyToContainAChangeableIdentifier] as? ReferenceTypeUsedOnlyToContainAChangeableIdentifier {\n self.id = referenceTypeUsedOnlyToContainAChangeableIdentifier.changeableIdentifier\n } else {\n self.id = "something went wrong"\n }\n }\n }\n\n let original: Image\n let small: Image\n // \xe2\x80\xa6\n\n init(from decoder: Decoder) throws {\n let container = try decoder.container(keyedBy: CodingKeys.self)\n id = try container.decode(String.self, forKey: .id)\n if let referenceTypeUsedOnlyToContainAChangeableIdentifier = decoder.userInfo[.referenceTypeUsedOnlyToContainAChangeableIdentifier] as? ReferenceTypeUsedOnlyToContainAChangeableIdentifier {\n referenceTypeUsedOnlyToContainAChangeableIdentifier.changeableIdentifier = id\n }\n }\n }\n}\n\n// Use this reference type to just store an id that's retrieved later.\nclass ReferenceTypeUsedOnlyToContainAChangeableIdentifier {\n var changeableIdentifier: String?\n}\n\n// Convenience extension.\nextension CodingUserInfoKey {\n static let referenceTypeUsedOnlyToContainAChangeableIdentifier = CodingUserInfoKey(rawValue: "\\(ReferenceTypeUsedOnlyToContainAChangeableIdentifier.self)")!\n}\n\nlet decoder = JSONDecoder()\n// Assign the reference type here to be used later during the decoding process first to assign the id in `Item` and then\n// later to retrieve that value in `Images`\ndecoder.userInfo[.referenceTypeUsedOnlyToContainAChangeableIdentifier] = ReferenceTypeUsedOnlyToContainAChangeableIdentifier()\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
751 次 |
| 最近记录: |