我对 Swift 中的 ARC 有疑问,请看下面的代码。
当出现
SecondViewController
时,将弹出警报,单击“确定”按钮后,
SecondViewController
将解散。这是我的问题,在我看来,SecondViewController
保留UIAlertController
,UIAlertController
保留UIAlertAction
,以及UIAlertAction
调用
back()
中的函数SecondViewController
。所以在这种情况下它可能会导致保留周期,并且根据视频here(大约8:30)它确实会导致保留周期。但是,当 SecondViewController
关闭时,调用 deinit
函数,它会打印 SecondViewController is being deinitializing
。所以我很困惑哪个是正确的。
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(title: "Hi", message: "everyone", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default) { _ in
self.back()
}
alert.addAction(ok)
self.present(alert, animated: true)
}
private func back() {
dismiss(animated: true)
}
deinit {
print("SecondViewController is being deinitializing")
}
}
这是另一个例子。我在 playground 中运行以下代码,当我将
deinit
设置为 nil 时,test
函数仍然被调用。我不明白为什么在[weak self]
函数中的value
之前不添加hehe()
就调用它。
class Test {
var int: Int = 0
func hehe() {
fetchAPI(input: 3) { value in
self.int = value
}
}
func fetchAPI(input: Int, completion: @escaping (Int) -> Void) {
completion(input)
}
deinit {
print("Test in being deinitializing")
}
}
var test: Test? = Test()
test?.hehe()
test = nil
我看过 Swift 文档,但找不到类似的例子。
我希望在我添加 [weak self] 之前不会调用
deinit
函数。我知道 ARC 不适用于值类型,但仍然不确定。有没有人可以对此进行更多解释?谢谢。
[更新]
这里是第三个例子,会造成retain cycle。我猜是因为
UIAlertController
和UIAlertAction
互相保留,而UIAlertAction
也保留了SecondViewController
。所以当 UIAlertController
dismiss 时,UIAlertAction
中的闭包仍然存在,这会导致保留循环。我说得对吗?
class SecondViewController: UIViewController {
var array: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
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!)
}
alertController.addAction(alertAction)
self.present(alertController, animated: true, completion: nil)
}
deinit {
print("SecondViewController is being deinitializing")
}
}
首先,检查 Playground 中的内存管理是没有意义的。游乐场以非常不寻常的方式运作。您无法在 Playground 中探索与内存、性能、线程或系统交互相关的任何内容。它们纯粹是为了玩弄算法和数据结构。
就是说,您描述的第一种情况是预料之中的。 SecondViewController 仅在 UIAlertController 出现时保留它(当它被关闭时,它被释放)。 UIAlertAction 仅在调用它之前保留其回调。之后它被释放。这是一种常见的模式,即抓住你需要的对象,直到你不再需要它们,然后释放它们。这确保对象在其生命周期内存在,然后可以被销毁。
您的测试示例非常相似,但更简单。
fetchAPI
返回后立即释放闭包,因为它从未分配给任何东西。你标记了它@escaping
,但它实际上并没有逃脱。