我在当前的项目中非常高兴地使用了Codable
s-一切都很好,我从盒子里得到的大部分东西都是内置的-完美的!不过,最近我无意中发现了第一个真正的问题,这个问题无法按照我想要的方式自动解决。
问题描述
我有一个来自后端的json,这是一个嵌套的东西。看起来像这样
{
"id": "fef08c8d-0b16-11e8-9e00-069b808d0ecc",
"title": "Challenge_Chapter",
"topics": [
{
"id": "5145ea2c-0b17-11e8-9e00-069b808d0ecc",
"title": "Automation_Topic",
"elements": [
{
"id": "518dfb8c-0b18-11e8-9e00-069b808d0ecc",
"title": "Automated Line examle",
"type": "text_image",
"video": null,
"challenge": null,
"text_image": {
"background_url": "",
"element_render": ""
}
},
{
"id": "002a1776-0b18-11e8-9e00-069b808d0ecc",
"title": "Industry 3.0 vs. 4.0: A vision of the new manufacturing world",
"type": "video",
"video": {
"url": "https://www.youtube.com/watch?v=xxx",
"provider": "youtube"
},
"challenge": null,
"text_image": null
},
{
"id": "272fc2b4-0b18-11e8-9e00-069b808d0ecc",
"title": "Classmarker_element",
"type": "challenge",
"video": null,
"challenge": {
"url": "https://www.classmarker.com/online-test/start/",
"description": null,
"provider": "class_marker"
},
"text_image": null
}
]
}
]
}
chapter是根对象,它包含一个主题列表,每个主题包含一个元素列表。很直截了当,但我被最底层的元素所束缚。每个元素都有一个来自后端的枚举,如下所示:
[ video, challenge, text_image ]
,但iOS应用程序不支持挑战,因此swift中的elementtype enum如下所示:public enum ElementType: String, Codable {
case textImage = "text_image"
case video = "video"
}
当然,它
throws
,因为首先发生的事情是它试图解码这个枚举的challenge
值,但它不在那里,所以我的整个解码失败。我想要什么
我只希望解码过程忽略无法解码的
Element
s。我不需要任何Optional
s。我只希望它们不出现在topic的元素数组中。我的推理和它的缺点
当然,我已经做了一些尝试来解决这个问题。第一个,最简单的一个是将
ElementType
标记为Optional
,但是在以后的这个方法中,我将不得不打开所有东西并处理这个-这是一个相当乏味的任务。我的第二个想法是在我的枚举中使用类似于.unsupported
的case,但是,再一次,稍后我想使用它生成单元格,我将不得不throw
或返回Optional
-基本上,与前面的想法相同。我的最后一个想法,但我还没有测试过,就是编写一个自定义的
init()
来进行解码,并在那里处理它,但是我不确定是Element
还是Topic
哪个应该对此负责?如果我把它写进Element
中,我什么也不能返回,我必须返回throw
,但是如果我把它放进Topic
中,我必须成功地解码要数组的元素。问题是,如果在某个时刻我将直接获取append
,我将无法在没有Elements
的情况下完成。TL;博士
我希望
throw
不是init(from decoder: Decoder) throws
,而是返回throw
。 最佳答案
我终于在SR-5953中找到了一些关于这个的东西,但我认为这是一个老套的。
无论如何,对于好奇的人允许这种有损解码你需要手动解码一切。您可以在init(from decoder: Decoder)
中编写它,但更好的方法是编写名为struct
的新助手。实施过程如下:
struct FailableCodableArray<Element: Decodable>: Decodable {
// https://github.com/phynet/Lossy-array-decode-swift4
private struct DummyCodable: Codable {}
private struct FailableDecodable<Base: Decodable>: Decodable {
let base: Base?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.base = try? container.decode(Base.self)
}
}
private(set) var elements: [Element]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var elements = [Element]()
if let count = container.count {
elements.reserveCapacity(count)
}
while !container.isAtEnd {
guard let element = try container.decode(FailableDecodable<Element>.self).base else {
_ = try? container.decode(DummyCodable.self)
continue
}
elements.append(element)
}
self.elements = elements
}
}
而对于那些失败元素的实际解码,您必须编写一个简单的
FailableCodableArray
实现,如:init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
elements = try container.decode(FailableCodableArray<Element>.self, forKey: .elements).elements
}
正如我所说,这个解决方案工作良好,但感觉有点老套。这是一个开放的错误,所以你可以投票给它,让斯威夫特团队看到,像这样的内置将是一个很好的补充!
关于json - 忽略不支持的可销毁物品,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48702444/