При использовании NSCoding
или NSKeyedArchiver
для отношения родитель-потомок; Я не могу установить ссылку на ребенка родительскому, так как он закончит сбой на Swift Playground.NSCoding - сохранение родительского атрибута вызывает сбой
Я хочу иметь ссылку в своем классе Child
классу Parent
.
Но это закончит сбой на игровой площадке, когда дело доходит до загрузки данных обратно в память.
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
В классе я хочу ссылку на родителя; так что в будущем я могу выполнять тесты или фильтрацию на дочерние объекты с определенными родителями.
Однако, я всегда получаю эту аварию на детской площадке:
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 сохранил родительский атрибут в дочернем объекте?
Большое спасибо
Edit: Refactored код
Этот рефакторинга кода, кажется, работает, хотя я не знаю, если я сделал это правильно.
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)")
}
}
Хорошо, я постараюсь реорганизовать мой код. Рекомендация сделать ссылки на родителя слабой ссылкой является хорошей. Я не думал об этом. Я попытаюсь реорганизовать свой код и посмотреть, где я нахожусь после этого – zardon
. Я обновил свой код.(1) Создал 'children' частный (set) var, (2) дочерние объекты не кодируют/декодируют родителя (3) функция для добавления дочерних элементов, которая устанавливает родительское свойство (4) родительское свойство является' слабым ' Код больше не падает, хотя я не знаю, сделал ли я все правильно. – zardon