使用 Codable 序列化包含引用循环的自定义 class
Use Codable to serialize custom class containing reference loop
我正在尝试序列化包含参考循环的自定义 class 并使用 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("\([=11=].name)\n\t Child: \([=11=].child?.name ?? "nil")\n\t Parent: \([=11=].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)
但我收到错误:
error: Execution was interrupted, reason: EXC_BAD_ACCESS
在最后一行。我认为它与参考循环有关,因为如果我注释掉以下行,它就会起作用:
per.parent = linda
那么我们可以使用 Codable 来序列化引用循环吗?如果是,怎么做?
您可以通过覆盖 Coding Keys
(from here)
选择序列化哪些属性
例如在你的情况下 class:
enum CodingKeys: String, CodingKey
{
case name
case child
}
只应保存此处包含的键,因此没有子->父循环。然而,这确实意味着在加载时连接将仅存在于一个方向,因此您必须在加载时 re-connect 它们。
FWIW,如果您要处理双向关系,使用数据库比使用 NSKeyedArchiver
持久化要好得多。
我正在尝试序列化包含参考循环的自定义 class 并使用 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("\([=11=].name)\n\t Child: \([=11=].child?.name ?? "nil")\n\t Parent: \([=11=].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)
但我收到错误:
error: Execution was interrupted, reason: EXC_BAD_ACCESS
在最后一行。我认为它与参考循环有关,因为如果我注释掉以下行,它就会起作用:
per.parent = linda
那么我们可以使用 Codable 来序列化引用循环吗?如果是,怎么做?
您可以通过覆盖 Coding Keys
(from here)
例如在你的情况下 class:
enum CodingKeys: String, CodingKey
{
case name
case child
}
只应保存此处包含的键,因此没有子->父循环。然而,这确实意味着在加载时连接将仅存在于一个方向,因此您必须在加载时 re-connect 它们。
FWIW,如果您要处理双向关系,使用数据库比使用 NSKeyedArchiver
持久化要好得多。