【问题标题】:Use Codable to serialize custom class containing reference loop使用 Codable 序列化包含引用循环的自定义类
【发布时间】:2018-03-01 22:36:37
【问题描述】:

我正在尝试序列化包含引用循环的自定义类并使用 NSCoding 使其工作:

import Foundation

class Person: NSObject, NSCoding {
    let name: String
    weak var parent: Person?
    var child: Person?
    init(name: String) {
        self.name = name
    }
    required init(coder aDecoder: NSCoder) {
        self.name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        self.parent = aDecoder.decodeObject(forKey: "parent") as? Person
        self.child =  aDecoder.decodeObject(forKey: "child") as? Person
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(parent, forKey: "parent")
        aCoder.encode(child, forKey: "child")
    }
}

let per = Person(name: "Per")
let linda = Person(name: "Linda")

linda.child = per
per.parent = linda

var people = [Person]()
people.append(linda)
people.append(per)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)

let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as! [Person]
myPeopleList.forEach({
    print("\($0.name)\n\t Child: \($0.child?.name ?? "nil")\n\t Parent: \($0.parent?.name ?? "nil")"

    )}) 
// Linda
//     Child: Per
//     Parent: nil
// Per
//     Child: nil
//     Parent: Linda

不,我想使用 Codable 做同样的事情:

import Foundation

class Person: Codable {
    let name: String
    weak var parent: Person?
    var child: Person?
    init(name: String) {
        self.name = name
    }
}

let per = Person(name: "Per")
let linda = Person(name: "Linda")
linda.child = per
per.parent = linda

var people = [Person]()
people.append(linda)
people.append(per)

let archiver = NSKeyedArchiver()
try archiver.encodeEncodable(people, forKey: NSKeyedArchiveRootObjectKey)

但我得到了错误:

错误:执行被中断,原因:EXC_BAD_ACCESS

在最后一行。我认为它与引用循环有关,因为如果我注释掉该行,它就会起作用:

per.parent = linda

那么我们可以使用 Codable 来序列化引用循环吗?如果有,怎么做?

【问题讨论】:

    标签: swift nskeyedarchiver codable


    【解决方案1】:

    您可以通过覆盖Coding Keys(from here)来选择要序列化的属性

    例如在你的情况下,在课堂上:

    enum CodingKeys: String, CodingKey
    {
        case name
        case child
    }
    

    只有这里包含的键应该被保存,所以没有 child->parent 循环。然而,这确实意味着加载时连接仅存在于一个方向,因此您必须在加载时重新连接它们。

    FWIW,如果您要处理双向关系,那么使用数据库而不是使用 NSKeyedArchiver 来实现持久性会好得多。

    【讨论】:

    • 感谢您的回复!我想我现在会使用 NSCoding。 (也许 Codable 将来会支持引用循环?)我只是使用 NSKeyedArchiver 创建一个 Data 对象来提供给 UIDocument。
    • 但是,是的,也许 UIManagedDocument 和 Core Data 更适合我的用例。谢谢!
    • 一般来说,如果您要使数据一般可编码/可解码,则关系一次只需要一个方向。任何其他关系通常由键处理,而不是层次结构。 GL 找到适合您的解决方案!
    猜你喜欢
    • 1970-01-01
    • 2012-07-03
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多