带有递归枚举的Swift Codable协议 [英] Swift Codable protocol with recursive enums
本文介绍了带有递归枚举的Swift Codable协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
让我们说我有一个像下面这样的模型,它使我可以构建Foo对象树。
Let's say that I have a model like the following, which allows me to build a tree of Foo objects.
struct Foo {
var kind : Kind
enum Kind {
case node([Foo])
case leaf
}
}
如何使此Codable成为专用于 case节点( [Foo])
?
How can I make this Codable, specifically for the case node([Foo])
?
推荐答案
这是基于@PauloMattos的答案的最终结构:
Here's the final struct, based on the answer from @PauloMattos:
基本Foo结构:
struct Foo {
var name: String
var kind: Kind
enum Kind {
case node([Foo])
case leaf
}
init(name: String, kind: Kind) {
self.name = name
self.kind = kind
}
}
可编码协议扩展:
extension Foo : Codable {
enum CodingKeys: String, CodingKey {
case name
case nodes
}
enum CodableError: Error {
case decoding(String)
case encoding(String)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
switch kind {
case .node(let nodes):
var array = container.nestedUnkeyedContainer(forKey: .nodes)
try array.encode(contentsOf: nodes)
break
case .leaf:
break
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Assumes name exists for all objects
if let name = try? container.decode(String.self, forKey: .name) {
self.name = name
self.kind = .leaf
if let array = try? container.decode([Foo].self, forKey: .nodes) {
self.kind = .node(array)
}
return
}
throw CodableError.decoding("Decoding Error")
}
}
CustomStringConvertable协议扩展(从树中输出字符串):
CustomStringConvertable Protocol extension (to output string from the tree):
extension Foo : CustomStringConvertible {
var description: String {
return stringDescription(self)
}
private func stringDescription(_ foo: Foo) -> String {
var string = ""
switch foo.kind {
case .leaf:
return foo.name
case .node(let nodes):
string += "\(foo.name): ("
for i in nodes.indices {
string += stringDescription(nodes[i])
// Comma seperate all but the last
if i < nodes.count - 1 { string += ", " }
}
string += ")"
}
return string
}
}
示例测试代码:
let a = Foo(name: "A", kind: .leaf)
let b = Foo(name: "B", kind: .leaf)
let c = Foo(name: "C", kind: .leaf)
let d = Foo(name: "D", kind: .node([b, c]))
let root = Foo(name: "ROOT", kind: .node([a, d]))
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let jsonData = try! encoder.encode(root)
let json = String(data: jsonData, encoding: .utf8)!
print("Foo to JSON:")
print(json)
let decoder = JSONDecoder()
do {
let foo = try decoder.decode(Foo.self, from: jsonData)
print("JSON to Foo:")
print(foo)
} catch {
print(error)
}
输出:
Foo to JSON:
{
"name" : "ROOT",
"nodes" : [
{
"name" : "A"
},
{
"name" : "D",
"nodes" : [
{
"name" : "B"
},
{
"name" : "C"
}
]
}
]
}
JSON to Foo:
ROOT: (A, D: (B, C))
这篇关于带有递归枚举的Swift Codable协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文