我遇到了一些奇特而有趣的东西,并希望得到任何人的意见。所以首先让我们来看看这个类的定义:
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
这里的问题是为什么在这种情况下不会被召唤?有什么不同之处,因为它基本上与第一种方法具有相同的参考分配?
我很想得到任何人的意见。
答案 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。
首先,您要创建从self
到bla
的强大参考:s1.add(bla)
其次,您可以创建从bla
到self
的强引用: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
。