child object 可以在 parent 的 deinit 期间引用它的 parent 吗?
Can a child object refer to its parent during deinit of the parent?
我有一个 parent class 和一个 child class。 parent 具有对 child 的强引用,而 child 具有对 parent 的无主引用。在 parent 的 deinit 期间,我希望 child 进行一些清理,这涉及调用 parent:
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
}
不幸的是,在 parent 的 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
据我了解,parent 应该仍然存在,因为 parent 的 deinit 尚未完成。然而,此错误似乎表明 child 无法再访问其对 parent 的 unowned
引用。
任何人都可以阐明这一点吗?
使用 unowned(unsafe)
修复了这个问题。总的来说这似乎很危险,但在这种情况下没关系,因为 parent 保证存在而 child 存在。
在这种情况下,unowned(unsafe) 会这样做。
但我个人不会将 unowned(unsafe) 用于桥接 objective-c 代码之外的任何东西。
如果可能的话,我会尽量避免从 deinit() 调用 child.doStuff()。我遇到过类似的情况,我只是添加了一个 .unload() 方法,我自己的代码负责在需要时调用该方法。在上面的例子中,ViewController 可以接受这个责任。
而且我想乌托邦式的解决方案是,找到一种方法,使对象在设计上不会如此交织在一起,when/if 当然是可能的。
unload() 场景示例:(我在终端 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
parent 将自身作为参数传递给需要它的 child 方法怎么样:
class Parent
{
deinit
{
child.doStuff(self)
}
}
class Child
{
func doStuff(parent)
{
println(parent)
}
}
我有一个 parent class 和一个 child class。 parent 具有对 child 的强引用,而 child 具有对 parent 的无主引用。在 parent 的 deinit 期间,我希望 child 进行一些清理,这涉及调用 parent:
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
}
不幸的是,在 parent 的 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
据我了解,parent 应该仍然存在,因为 parent 的 deinit 尚未完成。然而,此错误似乎表明 child 无法再访问其对 parent 的 unowned
引用。
任何人都可以阐明这一点吗?
使用 unowned(unsafe)
修复了这个问题。总的来说这似乎很危险,但在这种情况下没关系,因为 parent 保证存在而 child 存在。
在这种情况下,unowned(unsafe) 会这样做。 但我个人不会将 unowned(unsafe) 用于桥接 objective-c 代码之外的任何东西。
如果可能的话,我会尽量避免从 deinit() 调用 child.doStuff()。我遇到过类似的情况,我只是添加了一个 .unload() 方法,我自己的代码负责在需要时调用该方法。在上面的例子中,ViewController 可以接受这个责任。
而且我想乌托邦式的解决方案是,找到一种方法,使对象在设计上不会如此交织在一起,when/if 当然是可能的。
unload() 场景示例:(我在终端 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
parent 将自身作为参数传递给需要它的 child 方法怎么样:
class Parent
{
deinit
{
child.doStuff(self)
}
}
class Child
{
func doStuff(parent)
{
println(parent)
}
}