使用Codable序列化包含引用循环的自定义类

时间:2018-03-01 22:36:38

标签: swift nskeyedarchiver codable

我正在尝试序列化包含引用循环的自定义类,并使用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来序列化参考循环吗?如果是这样,怎么样?

1 个答案:

答案 0 :(得分:0)

您可以通过覆盖Coding Keys (from here)

来选择序列化的属性

e.g。在你的案例中:

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

只保存此处包含的密钥,因此没有子级>父循环。但这意味着连接只会在加载时在一个方向上存在,因此在加载时必须重新连接它们。

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