Deinit没有在涉及NSHashTable的特殊情况下被召唤

时间:2017-03-02 06:01:25

标签: swift automatic-ref-counting weak-references deinit

我遇到了一些奇特而有趣的东西,并希望得到任何人的意见。所以首先让我们来看看这个类的定义:

class TestClass:NSObject {  
    var s1 = NSHashTable<TestClass>(options: .weakMemory)  

    func doit(bla:TestClass) {  
        s1.add(bla)  
        bla.s1.add(self)  
    }  

    deinit {  
        print("Deinit")  
    }  
}  

现在让我们考虑以下事项:

var t1:TestClass? = TestClass()  
var t2:TestClass? = TestClass()  

如果我们做了以下deinit被调用:

t1?.s1.add(t2!)  
t2?.s1.add(t1!)  

t1 = nil // This will result in deinit being called  

现在让我们做同样的事情,但是通过调用doit()方法

t1?.doit(bla:t2!)  

t1 = nil // Deinit doesn't get called for some reason  

这里的问题是为什么在这种情况下不会被召唤?有什么不同之处,因为它基本上与第一种方法具有相同的参考分配?

我很想得到任何人的意见。

2 个答案:

答案 0 :(得分:1)

像往常一样,问题是您正试图在游乐场中测试 。别。游乐场是魔鬼的作品。

在实际的应用项目中进行测试,您会看到deinit被调用。

示例(iOS,但macOS中的等价物可以正常运行):

import UIKit

class TestClass:NSObject {
    var s1 = NSHashTable<TestClass>(options: .weakMemory)
    func doit(bla:TestClass) {
        s1.add(bla)
        bla.s1.add(self)
    }
    deinit {
        print("Deinit")
    }
}

class ViewController: UIViewController {
    var t1:TestClass? = TestClass()
    var t2:TestClass? = TestClass()

    override func viewDidLoad() {
        super.viewDidLoad()
        t1?.doit(bla:t2!)
        t1 = nil // --> "Deinit"
        print(t2?.s1) // --> it's empty
    }
}

答案 1 :(得分:0)

deinit未被调用,因为您已创建reference cycle

首先,您要创建从selfbla的强大参考:s1.add(bla)

其次,您可以创建从blaself的强引用:bla.s1.add(self)

现在他们都互相引用,所以如果你取消其中一个,他们就不会deinit

我已修改您的TestClass以删除参考周期:

class TestClass:NSObject {
  weak var s1 = NSHashTable<TestClass>(options: .weakMemory)

  func doit(bla:TestClass) {
    s1?.add(bla)
    bla.s1?.add(self)
  }

  deinit {
    print("Deinit")
  }
}

现在,您的第二个电话会正确触发deinit