英文:
KeyedDecodingContainerProtocol.superDecoder(forKey:) doesn't work as documentation says
问题
以下是您要翻译的内容:
我有以下由后端返回的 JSON:
```json
[
{
"id":8,
"title":"Title 1",
"componentCategoryIcon":{
"id":34,
"name":"icon_name_1",
"type":"IMAGE"
}
},
{
"id":8,
"title":"Title 2",
"componentCategoryIcon":{
"id":35,
"name":"icon_name_2",
"type":"IMAGE"
}
},
{
"id":8,
"title":"Title 3",
"componentCategoryIcon": null
}
]
以及以下的 Codable
结构体:
struct ComponentCategory: Codable {
let id: Int
let title: String
let componentCategoryIcon: Image?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(Int.self, forKey: .id)
self.id = id
self.title = try container.decode(String.self, forKey: .title)
let savedComponentCategory = (decoder.userInfo[.savedComponentCategories] as? [ComponentCategory])?.first(where: { $0.id == id })
// (1)
if let nestedDecoder = try? container.superDecoder(forKey: .componentCategoryIcon) {
self.componentCategoryIcon = try Image(from: nestedDecoder, savedImage: savedComponentCategory?.componentCategoryIcon)
} else {
self.componentCategoryIcon = nil
}
}
}
struct Image: Codable {
let id: Int
let name: String
let type: String?
let path: String?
let downloaded: Bool
required init(from decoder: Decoder, savedImage: Image?) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.type = try container.decodeIfPresent(String.self, forKey: .type)
self.path = try container.decodeIfPresent(String.self, forKey: .path)
self.downloaded = try container.decodeIfPresent(Bool.self, forKey: .downloaded) ?? savedImage?.downloaded ?? false
}
}
现在,我注意到了与 superDecoder(forKey:)
函数文档不同的行为。文档中说:
抛出
如果给定键的值为 null,则抛出
DecodingError.valueNotFound
。
在第三次解码 ComponentCategory
时(componentCategoryIcon
为 null
),我预期会进入(1)if-else
的 else 分支。但实际上,我得到了一个似乎有效的 nestedContainer
并且在 Image
的初始化中出现了异常。
我是否误解了 superDecoder(forKey:)
文档?还是文档有错误?
英文:
I have the following JSON returned by my backend:
[
{
"id":8,
"title":"Title 1",
"componentCategoryIcon":{
"id":34,
"name":"icon_name_1",
"type":"IMAGE"
}
},
{
"id":8,
"title":"Title 2",
"componentCategoryIcon":{
"id":35,
"name":"icon_name_2",
"type":"IMAGE"
}
},
{
"id":8,
"title":"Title 3",
"componentCategoryIcon": null
}
]
And the following Codable
structs:
struct ComponentCategory: Codable {
let id: Int
let title: String
let componentCategoryIcon: Image?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(Int.self, forKey: .id)
self.id = id
self.title = try container.decode(String.self, forKey: .title)
let savedComponentCategory = (decoder.userInfo[.savedComponentCategories] as? [ComponentCategory])?.first(where: { $0.id == id })
// (1)
if let nestedDecoder = try? container.superDecoder(forKey: .componentCategoryIcon) {
self.componentCategoryIcon = try Image(from: nestedDecoder, savedImage: savedComponentCategory?.componentCategoryIcon)
} else {
self.componentCategoryIcon = nil
}
}
}
struct Image: Codable {
let id: Int
let name: String
let type: String?
let path: String?
let downloaded: Bool
required init(from decoder: Decoder, savedImage: Image?) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.type = try container.decodeIfPresent(String.self, forKey: .type)
self.path = try container.decodeIfPresent(String.self, forKey: .path)
self.downloaded = try container.decodeIfPresent(Bool.self, forKey: .downloaded) ?? savedImage?.downloaded ?? false
}
Now I noted a behaviour different from documentation for superDecoder(forKey:)
func. Documentation says:
> Throws
>
> DecodingError.valueNotFound
if self
has a null entry for the given key.
During third ComponentCategory
decoding (componentCategoryIcon
is null
), I expected to go to else branch of the (1) if-else
. Instead I obtain an apparently valid nestedContainer
and I have an exception in the Image
init.
Am I misunderstanding superDecoder(forKey:)
documentation? Or is it wrong?
答案1
得分: 1
The current implementation确实不会在没有给定键的情况下引发错误,而是返回一个空容器;文档与此实现不匹配。似乎即将推出的swift-foundation
包也保持了这种行为,所以文档需要更新。
这很可能值得提出一个问题(无论是用于修复错误还是修复文档)。
与此同时,您可以通过检查所需键的显式存在来解决此问题,并将其用作if语句的条件。
尽管如上面的评论所述,您尝试使用superDecoder
似乎令人惊讶。您可以考虑要么在您的问题中添加有关为什么需要这样做的信息,要么提出一个新问题,询问您可能希望采取的其他方法建议。
英文:
The current implementation indeed does not throw an error if there is no value for the given key, and instead returns an empty container; the documentation does not match this implementation. It appears that the upcoming swift-foundation
package also maintains this behavior, so the documentation stands to get updated.
This is likely worth filing an issue for (whether for a bug fix, or a documentation fix).
In the meantime, you can work around this by checking for the explicit existence of the key you need, and use that as the condition for your if-statement.
This being said, like the comments above mention, it seems surprising you would try to use a superDecoder
for this. You may want to either add information to your question about why you need to do this, or open a new question asking for suggestions on what approach you might want to take instead.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论