在父母去世期间,子对象可以引用其父对象吗?

时间:2015-05-29 08:13:05

标签: swift deinit

我有一个父类和一个子类。父母对孩子有强烈的引用,孩子对父母有无主要的引用。在父母去世期间,我希望孩子做一些清理,这涉及到打电话给父母:

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引用。

任何人都可以对此有所了解吗?

3 个答案:

答案 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)修复此问题。一般来说这似乎很危险,但在这种情况下它是可以的,因为在孩子存在的情况下父母可以保证存在。