Deinit 不调用 - 找不到保留某些内容的原因(提供的代码)

Deinit not calling - Cannot find why something is retaining (code provided)

我发现在以下情况下我的 UIViewcontroller 没有调用 deinit()。 我正在使用此代码扩展通过添加点击手势识别器让我的生活更轻松。

https://gist.github.com/saoudrizwan/548aa90be174320fbaa6b3e71f01f6ae

我已经在我的 VC 之一中使用了这段代码,我已经将其精简到最少的代码量:

viewDidLoad() 中我这样做了:

// When the user taps on a label, have its related textbox automatically get the caret so they can type
// Add tapping so when you tap on a label it makes the corresponding textbox first responder
lblSubject.addTapGestureRecognizer {
 self.txtSubject.becomeFirstResponder()
}

似乎是行:

self.txtSubject.becomeFirstResponder()

是问题所在 - 当我在那个闭包中留下上面这一行时,deinit() 没有调用我的 VC。 当我删除上面的行或将其替换为 print("hello world") 之类的内容时 deinit()正确调用。 txtSubject 是 @IBOutlet weak var txtSubject: UITextField!

我不太确定在这里做什么。我读到当你触发 becomeFirstResponder() 时调用 resignFirstResponder() 很重要,但即使我不点击标签(以免给 becomeFirstResponder() 一个调用的机会)我仍然打不中 deinit()

有什么我可以进一步研究的想法吗?

非常感谢。

这是一个经典的保留循环。闭包内部的 self. 是为了提醒您考虑这一点。我假设 self 保留了 lblSubject,并且(通过 OBJC_ASSOCIATION_RETAIN 关联的键),lblSubject 保留了 self 因为它被这个闭包捕获了。

不过,您实际上并不需要 self。你只需要txtSubject。所以你可以捕捉到:

lblSubject.addTapGestureRecognizer { [txtSubject] in
    txtSubject.becomeFirstResponder()
}

或者,您可以退回到巨型 weak self 锤子(尽管这往往被过度使用):

lblSubject.addTapGestureRecognizer { [weak self] in
    self?.txtSubject.becomeFirstResponder()
}

探索此类错误的最佳方法是使用 Xcode 的 Memory Graph

查看 Automatic Reference Counting 上的 Swift 文档也是一个好主意。

改变

self.txtSubject.becomeFirstResponder()

[unowned self] in self.txtSubject.becomeFirstResponder()

unowned 通常被认为是危险的,但这里没有危险。如果 self 不复存在,将没有任何东西可以挖掘,代码将永远不会 运行.