1

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

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()

有什么想法可以让我进一步了解吗?

非常感谢。

4

2 回答 2

3

改变

self.txtSubject.becomeFirstResponder()

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

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

于 2021-04-17T21:31:44.027 回答
2

这是一个经典的保留循环。封闭的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 文档也是一个好主意。

于 2021-04-17T14:41:46.387 回答