当使用 NSCoding
或 NSKeyedArchiver
建立父子关系时;我无法在子项中设置对父项的引用,因为它最终会在 Swift Playground 上崩溃。
我想在我的 Child
类中引用我的 Parent
类。
但在将数据加载回内存时,它最终会在 Playground 上崩溃。
class Parent: NSObject, NSCoding {
var children:[Child] = [Child]()
init(children:[Child]?) {
if let childrenList = children {
self.children = childrenList
}
}
public convenience required init?(coder aDecoder: NSCoder) {
let children = aDecoder.decodeObject(forKey: "children") as! [Child]
self.init(children: children)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(children, forKey:"children")
}
}
class Child: NSObject, NSCoding {
var parent: Parent
init(parent:Parent) {
self.parent = parent
}
public convenience required init?(coder aDecoder: NSCoder) {
let parent = aDecoder.decodeObject(forKey: "parent") as! Parent
self.init(parent: parent)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(parent, forKey:"parent")
}
}
var parent1 = Parent.init(children: nil)
var parent2 = Parent.init(children: nil)
var child1 = Child.init(parent: parent1)
var child2 = Child.init(parent: parent2)
parent1.children.append(child1)
parent2.children.append(child2)
let parents = [parent1, parent2]
let manager = FileManager.default
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first! as URL
let writeFile: URL = url.appendingPathComponent("sample.data")
print ("Attempting to write to: \(writeFile.path)")
NSKeyedArchiver.archiveRootObject(parents, toFile: writeFile.path)
// Crash occurs here.
if let parentData = NSKeyedUnarchiver.unarchiveObject(withFile: writeFile.path) as? [Parent] {
for p in parentData {
print ("\(p.children.count)")
}
}
在 Child
类中,我想引用父类;以便将来我可以与某些 parent 一起对子对象进行测试或过滤。
但是,我总是在 Playground 上遇到这个崩溃:
Playground execution aborted: error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x10). The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
它似乎在引用父对象时崩溃。
如何确保 NSCoding 将我的父属性保存在子对象中?
非常感谢
编辑:重构代码
这段重构代码似乎可以工作,但我不知道我是否做对了。
class Parent: NSObject, NSCoding {
private (set) var children:[Child] = [Child]()
override init() {
super.init()
}
public convenience required init?(coder aDecoder: NSCoder) {
let children = aDecoder.decodeObject(forKey: "children") as! [Child]
self.init()
self.createChildren(children: children)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(children, forKey:"children")
}
func addChild(child:Child) {
child.parent = self
self.children.append(child)
}
private func createChildren(children:[Child]) {
for child:Child in children {
self.addChild(child: child)
}
}
}
class Child: NSObject, NSCoding {
weak var parent: Parent?
override init() {
super.init()
}
public convenience required init?(coder aDecoder: NSCoder) {
self.init()
}
func encode(with aCoder: NSCoder) {
}
}
var parent1 = Parent.init()
var parent2 = Parent.init()
var child1 = Child.init()
var child2 = Child.init()
parent1.addChild(child: child1)
parent2.addChild(child: child2)
let parents = [parent1, parent2]
let manager = FileManager.default
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first! as URL
let writeFile: URL = url.appendingPathComponent("sample.data")
print ("Attempting to write to: \(writeFile.path)")
NSKeyedArchiver.archiveRootObject(parents, toFile: writeFile.path)
if let parentData = NSKeyedUnarchiver.unarchiveObject(withFile: writeFile.path) as? [Parent] {
for p in parentData {
print ("\(p.children.count)")
}
}
最佳答案
仔细思考您的代码中当前发生的事情。您存档父级。 parent 存档其 child 。然后,这些 child 中的每一个都试图存档其 parent 。然后每个 parent 都试图存档其 child 。这个循环然后继续下去,直到它“繁荣”。
你有几个问题:
- 在您的
Child
类中,parent
属性需要weak
。否则,您会遇到引用循环和大量内存问题。 - 您的
子
类不应尝试编码/解码其父类。 - 您的
Parent
类应该在解码父级时将自己设置为每个子级的父级。
您的崩溃是由于违反问题 2 导致的。
作为问题 3 的旁注,我将重构您的代码。创建 child 时不要传递 parent 。并且不要直接在您的 Parent
类中公开 children
数组。我会向 Parent
类添加方法以添加和获取子项。添加子项的方法应设置添加到其中的每个子项的 parent
属性。
关于arrays - NSCoding - 保存父属性导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41538831/