【问题标题】:Swift Tree Structure, encoding and accessing nodesSwift 树结构、编码和访问节点
【发布时间】:2022-01-23 00:56:36
【问题描述】:

我无法弄清楚为什么以下内容不运行。目标是创建一个可以保存到 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)!)

【问题讨论】:

    标签: json swift tree codable


    【解决方案1】:

    问题在于默认情况下Codable 尝试编码/解码符合类型的所有属性。这意味着孩子尝试编码/解码他们的父母,父母也包含孩子,因此导致无限循环。

    您需要通过提供符合CodingKey 的类型手动指定要编码/解码的属性。通过从Node.CodingKeysMyData.CodingKeys 中省略parent 属性,您可以解决无限循环。

    import Foundation
    
    final class Node: Codable {
        let id = UUID()
        var data: [MyData]
        var children: [Node]
        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
        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)!)
    

    【讨论】:

    • 太棒了!就是这样。现在就像一个魅力 - 感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2018-12-03
    • 2014-12-21
    相关资源
    最近更新 更多