and*_*ypf 6 grand-central-dispatch ios retain-cycle
我试图更好地理解保留周期,特别是相对于Dispatch Queues.我正在使用AVFoundation并在sessionQueue上管理AVCaptureSession:
private let sessionQueue = DispatchQueue(label: "com.andrewferrarone.sessionQueue")
Run Code Online (Sandbox Code Playgroud)
在Apple文档中的很多代码示例中我看到了:
self.sessionQueue.async { [unowned self]
//
}
Run Code Online (Sandbox Code Playgroud)
[unowned self]这里的自我是必要的吗?self(viewController)引用self.sessionQueue和调度闭包以 self.sessionQueue捕获self.这是一个参考周期吗?self不引用闭包,只是DispatchQueue.如果[unowned self]有必要,那么根据我的理解,我只想使用,unowned self如果我确定自我不会是零.所以,假设我把一个任务sessionQueue花了很长时间,并且viewController被弹出并在任务完成之前被释放?会发生什么sessionQueue和任务?如果它仍然在那时,当它试图访问自己时,应用程序将崩溃.另一方面,由于无主的self不会增加self的保留计数,因此它不会阻止viewController被释放.
所以我的问题是当一个viewController被解除分配时DispatchQueues会发生什么,以及在这种情况下会发生什么,如果一个viewController在dispatchQueue任务完成之前被解除分配?如果有人能够对这里发生的事情有所了解,那将非常有帮助和赞赏.
谢谢你帮助我的朋友们!
Rob*_*Rob 18
[unowned self]这里的自我是必要的吗?
不仅使用[unowned self]不必要,而且在异步调度块中非常危险.你最终得到了一个指向解除分配对象的悬空指针.
如果您不想self在异步调用中保持强引用[weak self],请改用.只有unowned在知道在self释放后才能调用块时才应该使用.显然,使用异步调用,您不知道这一点,因此[unowned self]不应该在该上下文中使用.
无论您是使用[weak self]还是使用强引用,都是一个问题,您是否需要异步执行的块来保持对相关对象的强引用.例如,如果您只更新视图控制器的视图控件,那么[weak self]就可以了(更新已被解除的视图没有意义).
更重要的用途weak和unowned参考是避免强参考周期.但这并不适用于您提供的示例.如果视图控制器保留对块本身的一些引用(例如,你有一些闭包属性)和那些闭包引用self,但没有weak/ unownedqualifier ,你只需要担心这些周期.
我的问题是
DispatchQueue当取消分配视图控制器时会发生什么?
这些队列将继续存在,任何已调度的块也将继续存在,直到(a)所有已发送的块完成; (b)没有更强烈的队列引用.
因此,如果异步调度带有weak引用的块self(即视图控制器),它们将在视图控制器释放后继续运行.这就是为什么unowned在这种情况下不使用它是至关重要的.
对于它的价值,经验测试可能是有启发性的.考虑:
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let queue = DispatchQueue(label: "com.domain.app.SecondViewController")
for i in 0 ..< 10 {
queue.async { [weak self] in
print("closure \(i) start")
self?.performSomeTask(i)
print("closure \(i) finish")
}
}
}
private func performSomeTask(_ value: Int) {
print("performSomeTask starting \(value)")
Thread.sleep(forTimeInterval: 5) // you wouldn't generally `sleep`, but merely for diagnostic purposes
print("performSomeTask finishing \(value)")
}
deinit {
print("deinit SecondViewController")
}
}
Run Code Online (Sandbox Code Playgroud)
如果在调度的块排队并运行时关闭此视图控制器,您将看到:
使用时[weak self],视图控制器仅在当前调度块完成之前保留,然后视图控制器将被释放,其余的块将快速启动,但由于[weak self],performSomeTask在视图控制器被解除后将不会运行.
如果替换weak为unowned(并且显然删除了?in self?.performSomeTask(...)),如果在排队的块有机会启动之前关闭视图控制器,则会看到它崩溃.这说明了为什么[unowned self]异步代码如此危险.
如果您只是[weak self]完全删除并让它使用隐式强引用self,您将看到它将不会释放视图控制器,直到所有排队的块完成.
| 归档时间: |
|
| 查看次数: |
1808 次 |
| 最近记录: |