我发现我的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()
正确调用。txt主题为@IBOutlet weak var txtSubject: UITextField!
我不完全确定在这里该做什么。我读到,当你触发becomeFirstResponder()
时,你调用resignFirstResponder()
很重要,但即使我不点击标签(以免给becomeFirstResponder()
打电话的机会(,我仍然无法达到deinit()
有什么想法我可以进一步了解吗?
非常感谢。
更改
self.txtSubject.becomeFirstResponder()
至
[unowned self] in self.txtSubject.becomeFirstResponder()
unowned
通常被认为是危险的,但这里没有危险。如果self
不存在,就没有什么可挖掘的,代码也永远不会运行。
这是一个经典的保留循环。闭包内部的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()
}
探索这种bug的最好方法是使用Xcode的内存图。
查看Swift关于自动参考计数的文档也是一个好主意。