我有一个父类和一个子类。父母对孩子有强烈的引用,孩子对父母有无主要的引用。在父母去世期间,我希望孩子做一些清理,这涉及到打电话给父母:
class ViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
let parent = Parent()
}
}
class Parent : NSObject
{
override init()
{
super.init()
child.doStuff()
}
deinit
{
child.doStuff()
}
lazy private var child : Child = Child(parent : self)
}
class Child : NSObject
{
init(parent : NSObject)
{
self.parent = parent
}
func doStuff()
{
println(self.parent)
}
deinit
{
}
private unowned var parent : NSObject
}
不幸的是,在父母的deinit期间调用doStuff()
会导致崩溃,因为它使用self.parent
:
libswiftCore.dylib`_swift_abortRetainUnowned:
0x111e91740 <+0>: leaq 0x1e6cd(%rip), %rax ; "attempted to retain deallocated object"
0x111e91747 <+7>: movq %rax, 0x58612(%rip) ; gCRAnnotations + 8
0x111e9174e <+14>: int3
-> 0x111e9174f <+15>: nop
据我了解,父母应该仍然存在,因为父母的deinit尚未完成。然而,这个错误似乎表明孩子无法再访问其对父母的unowned
引用。
任何人都可以对此有所了解吗?
答案 0 :(得分:1)
在这种情况下,无主(不安全)会这样做。 但我个人不会使用无主(不安全),除了桥接Objective-c代码。
如果可能的话,我会尽量避免从deinit()调用child.doStuff()。我有类似的情况,我只是添加了一个.unload()方法,我自己的代码负责在需要时调用。在上面的示例中,ViewController可以接受此责任。
我想乌托邦式的解决方案是找到一种方式,在这种情况下,当/如果可能的话,对象不会被设计交织在一起。
卸载()场景示例:(我在终端repl中测试过它,因此没有UIKit)
import Foundation
class ViewController {
let parent = Parent()
deinit {
parent.unload()
}
}
class Parent {
init() {
child.doStuff()
}
func unload() {
// Code used to be in deinit
child.doStuff()
}
lazy private var child : Child = Child(parent : self)
}
class Child {
init(parent : Parent) {
self.parent = parent
}
func doStuff() {
println(self.parent)
}
private unowned var parent : Parent
}
var vc:ViewController? = ViewController()
vc = nil
答案 1 :(得分:1)
父亲如何将自己作为参数传递给需要它的孩子的方法:
class Parent
{
deinit
{
child.doStuff(self)
}
}
class Child
{
func doStuff(parent)
{
println(parent)
}
}
答案 2 :(得分:0)
使用unowned(unsafe)
修复此问题。一般来说这似乎很危险,但在这种情况下它是可以的,因为在孩子存在的情况下父母可以保证存在。