Swift 在特殊情况下,不需要使用脱硝剂,这涉及到不可清洗性

Swift 在特殊情况下,不需要使用脱硝剂,这涉及到不可清洗性,swift,automatic-ref-counting,weak-references,deinit,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 {

我遇到了一些奇特有趣的东西,我很想从任何人那里得到信息。因此,首先让我们对类进行以下定义:

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

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

    deinit {  
        print("Deinit")  
    }  
}  
如果我们执行以下操作,Denit将被调用:

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

t1 = nil // This will result in deinit being called  
现在让我们通过调用doit()方法来做同样的事情

这里的问题是为什么在这种情况下不叫Denit?因为它本质上与第一个方法具有相同的引用赋值,所以它有什么不同


我很想从任何人那里得到关于这个的信息。

deinit
不会被调用,因为您已经创建了

首先,您要创建一个从
self
bla
的强大引用:
s1。添加(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")
  }
}
类TestClass:NSObject{
弱变量s1=NSHashTable(选项:。弱内存)
func doit(bla:TestClass){
s1?添加(bla)
bla.s1?添加(自身)
}
脱硝{
印刷品(“脱硝”)
}
}

现在,您的第二次呼叫将正确触发Denit。

与往常一样,问题是您正试图在操场上测试此功能。不要。操场是魔鬼的杰作

在实际的应用程序项目中进行测试,您将看到调用了
deinit

示例(iOS,但macOS中的等效版本也可以):

导入UIKit
类TestClass:NSObject{
变量s1=NSHashTable(选项:.weakMemory)
func doit(bla:TestClass){
s1.添加(bla)
bla.s1.添加(自身)
}
脱硝{
印刷品(“脱硝”)
}
}
类ViewController:UIViewController{
变量t1:TestClass?=TestClass()
变量t2:TestClass?=TestClass()
重写func viewDidLoad(){
super.viewDidLoad()
t1?.doit(bla:t2!)
t1=nil/-->“脱硝”
打印(t2?.s1)/-->它是空的
}
}

您是如何测试代码的?行
t1?.doit(t2!)
未在Swift 3中编译。就我测试而言,两个代码(
t1?.doit(t2!)
固定为
t1?.doit(bla:t2!)
)在
t1=nil行显示了
Deinit
。(Xcode 8.2.1,命令行工具项目)我无法在Swift 3.0.2或Swift 3.1.1中复制此内容code@OOPer我在操场上运行了
doit()
方法调用(相同的xcode版本),而
Deinit
根本没有打印出来。它只使用第一种方法打印。没有引用循环,因为
NSHashTable
包含对添加对象的弱引用。您可以自己测试:
t1?.doit(t2!)print(“t1=\(t1!)”)t1=nil print(t2!.s1.allObjects)//在这里您将看到t1地址
no,正如我所期望的那样,我刚刚打印了
[]
,当
选项提供了weakMemory
时,哈希表包含对添加对象的弱引用:
(请随意)。我看到了选项,但对我来说,即使我对@Hamish执行了
t1=nil
,它仍然存在,这就是将s1设置为
.weakMemory
的要点,以便所持有的引用是弱关系。因为它们被弱持有
t1=nil
应该能够被释放
t1?.doit(bla:t2!)  

t1 = nil // Deinit doesn't get called for some reason  
class TestClass:NSObject {
  weak var s1 = NSHashTable<TestClass>(options: .weakMemory)

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

  deinit {
    print("Deinit")
  }
}
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
    }
}