Swift 树结构、编码和访问节点
Swift Tree Structure, encoding and accessing nodes
我无法弄清楚为什么以下内容没有 运行。目标是创建一个具有引用类型的树结构,可以将其保存到 json 文件中,但以下 playground 代码不会 运行.
根节点的父节点为 nil,但我认为编码器忽略了 nil 值。在我的应用程序中,我得到一个 EXC_BAD_ACCESS。这是否需要使用结构而不是 类 来完成,如果是这样,是否有一种方法可以在不遍历整个树的情况下访问特定节点?任何帮助表示赞赏。
import Cocoa
final class Node: Codable {
var id: UUID
var data: [MyData]
var children: [Node]
var parent: Node? = nil
init() {
self.id = UUID()
self.data = []
self.children = []
}
func add(data: MyData) {
data.parent = self
self.data.append(data)
}
func add(child: Node) {
child.parent = self
self.children.append(child)
}
}
final class MyData: Codable {
var id: UUID
var label: String
var value: String
var parent: Node? = nil
init(label: String, value: String) {
self.id = UUID()
self.label = label
self.value = value
}
}
var root = Node()
root.add(data: MyData(label: "label 1", value: "value 1"))
root.add(data: MyData(label: "label 2", value: "value 2"))
var child = Node()
child.add(data: MyData(label: "label 3", value: "value 3"))
root.add(child: child)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let json = try encoder.encode(root)
print(String(data: json, encoding: .utf8)!)
问题是默认情况下 Codable
尝试 encode/decode 所有 一致类型的属性。这意味着 children 尝试 encode/decode 他们的 parent,其中 parent 也包含 children,因此导致无限循环。
您需要通过提供 CodingKey
一致类型手动指定 encode/decode 的属性。通过从 Node.CodingKeys
和 MyData.CodingKeys
中省略 parent
属性,您解决了无限循环。
import Foundation
final class Node: Codable {
let id = UUID()
var data: [MyData]
var children: [Node]
weak var parent: Node? = nil
init() {
self.data = []
self.children = []
}
func add(data: MyData) {
data.parent = self
self.data.append(data)
}
func add(child: Node) {
child.parent = self
self.children.append(child)
}
private enum CodingKeys: String, CodingKey {
case data
case children
}
}
final class MyData: Codable {
let id = UUID()
var label: String
var value: String
weak var parent: Node? = nil
init(label: String, value: String) {
self.label = label
self.value = value
}
private enum CodingKeys: String, CodingKey {
case label
case value
}
}
var root = Node()
root.add(data: MyData(label: "label 1", value: "value 1"))
root.add(data: MyData(label: "label 2", value: "value 2"))
var child = Node()
child.add(data: MyData(label: "label 3", value: "value 3"))
root.add(child: child)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let json = try encoder.encode(root)
print(String(data: json, encoding: .utf8)!)
我无法弄清楚为什么以下内容没有 运行。目标是创建一个具有引用类型的树结构,可以将其保存到 json 文件中,但以下 playground 代码不会 运行.
根节点的父节点为 nil,但我认为编码器忽略了 nil 值。在我的应用程序中,我得到一个 EXC_BAD_ACCESS。这是否需要使用结构而不是 类 来完成,如果是这样,是否有一种方法可以在不遍历整个树的情况下访问特定节点?任何帮助表示赞赏。
import Cocoa
final class Node: Codable {
var id: UUID
var data: [MyData]
var children: [Node]
var parent: Node? = nil
init() {
self.id = UUID()
self.data = []
self.children = []
}
func add(data: MyData) {
data.parent = self
self.data.append(data)
}
func add(child: Node) {
child.parent = self
self.children.append(child)
}
}
final class MyData: Codable {
var id: UUID
var label: String
var value: String
var parent: Node? = nil
init(label: String, value: String) {
self.id = UUID()
self.label = label
self.value = value
}
}
var root = Node()
root.add(data: MyData(label: "label 1", value: "value 1"))
root.add(data: MyData(label: "label 2", value: "value 2"))
var child = Node()
child.add(data: MyData(label: "label 3", value: "value 3"))
root.add(child: child)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let json = try encoder.encode(root)
print(String(data: json, encoding: .utf8)!)
问题是默认情况下 Codable
尝试 encode/decode 所有 一致类型的属性。这意味着 children 尝试 encode/decode 他们的 parent,其中 parent 也包含 children,因此导致无限循环。
您需要通过提供 CodingKey
一致类型手动指定 encode/decode 的属性。通过从 Node.CodingKeys
和 MyData.CodingKeys
中省略 parent
属性,您解决了无限循环。
import Foundation
final class Node: Codable {
let id = UUID()
var data: [MyData]
var children: [Node]
weak var parent: Node? = nil
init() {
self.data = []
self.children = []
}
func add(data: MyData) {
data.parent = self
self.data.append(data)
}
func add(child: Node) {
child.parent = self
self.children.append(child)
}
private enum CodingKeys: String, CodingKey {
case data
case children
}
}
final class MyData: Codable {
let id = UUID()
var label: String
var value: String
weak var parent: Node? = nil
init(label: String, value: String) {
self.label = label
self.value = value
}
private enum CodingKeys: String, CodingKey {
case label
case value
}
}
var root = Node()
root.add(data: MyData(label: "label 1", value: "value 1"))
root.add(data: MyData(label: "label 2", value: "value 2"))
var child = Node()
child.add(data: MyData(label: "label 3", value: "value 3"))
root.add(child: child)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let json = try encoder.encode(root)
print(String(data: json, encoding: .utf8)!)