0

我有一个父类和一个子类。父级对子级有强引用,子级对父级有无主引用。在父母的 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
}

不幸的是,doStuff()在父进程的 deinit 期间调用会导致崩溃,因为它使用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父母的引用。

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

4

3 回答 3

1

在这种情况下 unowned(unsafe) 会这样做。但我个人不会将 unowned(unsafe) 用于桥接 Objective-c 代码之外的任何东西。

如果可能的话,我会尽量避免从 deinit() 调用 child.doStuff() 的需要。我遇到过类似的情况,我只是添加了一个 .unload() 方法,我自己的代码负责在需要时调用该方法。在上面的例子中,ViewController 可以接受这个责任。

我想乌托邦式的解决方案是,如果可能的话,当然要找到一种方法,使对象不会被设计如此交织在一起。

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
于 2015-05-29T09:45:17.333 回答
1

父母如何将自己作为参数传递给需要它的孩子方法:

class Parent
{
    deinit
    {
        child.doStuff(self)
    }
}

class Child
{
    func doStuff(parent)
    {
        println(parent)
    }
}
于 2015-05-29T22:33:20.893 回答
0

使用unowned(unsafe)修复了这个问题。一般来说,这似乎很危险,但在这种情况下,这没关系,因为当孩子存在时,父母肯定存在。

于 2015-05-29T08:45:52.030 回答