最近,遇到一个问题:使用 UIAlertController 时 action 中的 handler 是否需要 weak self。
retain cycle
循环引用的发生是因为两个对象之间互相存在强的引用,那么系统根据引用计数进行内存管理的时候就会遇到内存泄漏的问题。
据此,我们逐一来看以下不同场景。以下场景的前提是: 通过 UINavigationController push 一个新建的 UIViewController A,然后在此页面弹出 Alert,点击确认后,再返回到上一个页面。
场景一
let alertAction = UIAlertAction.init(title: "OK", style: .default) { (action) in
self.p_someAction()
print("print array: \(self.array)")
}
let alertController = UIAlertController.init(title: "Test", message: nil, preferredStyle: .alert)
alertController.addAction(alertAction)
self.present(alertController, animated: true, completion: nil)
这种情况下,当 A pop后,内存会得到正确地释放,因为 self 和 alertAction 互相之间并不持有。虽然 alertAction 强引用 self,且被添加到 alertController,但是 UIAlertController 的内部实现会去清理内存。也就是说,当点击 “OK” 后,UIAlertController 会对 action 清理,从而不会强引用 self。
场景二
再看场景一的变形:
let alertAction = UIAlertAction.init(title: "OK", style: .default) { (action) in
self.p_someAction()
print("print array: \(self.array)")
}
let alertController = UIAlertController.init(title: "Test", message: nil, preferredStyle: .alert)
alertController.addAction(alertAction)
self.present(alertController, animated: true, completion: nil)
self.alertController = alertController
这种情况下,当 A pop后,A 的内存不会得到释放。当点击 “OK” 后,因为因为 alertController 现在是一个熟悉,系统并不会去尝试清理 alertController 内存,这样导致 alertController 强引用着 self,造成 self 和 alertController 之间互相强引用。
此时,需要在 hanlder 中添加 [weak self]。
场景三
假设 action 的 handler 中使用到了 alertController :
let alertController = UIAlertController.init(title: "Test", message: nil, preferredStyle: .alert)
alertController.addTextField(configurationHandler: nil)
let alertAction = UIAlertAction.init(title: "OK", style: .default) { (action) in
let text = alertController.textFields![0].text
self.array.append(text!)
print("print array: \(self.array)")
}
alertController.addAction(alertAction)
self.present(alertController, animated: true, completion: nil)
这里,我们添加了一个文本输入框,模拟点击确定后提交用户输入的文本。在这种情况下,A pop 后,A 的内存不会得到释放。因为 alertAction 的 handler 中同时有 self 和 alertController,这造成了 alertController 强引用了 self,此时也需要添加 [weak self]。
结论
无论何时,使用 [weak self] 都是安全的做法;大多数情况下,无需持有 UIAlertController 。
Comments