当UIViewController被取消分配时,Dispatch Queues会发生什么? [英] What happens to Dispatch Queues when UIViewController is Deallocated?

查看:126
本文介绍了当UIViewController被取消分配时,Dispatch Queues会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图更好地理解保留周期,特别是相对于Dispatch Queues。我正在使用AVFoundation并在sessionQueue上管理AVCaptureSession:

I am trying to better understand retain cycles, especially relative to Dispatch Queues. I am working with AVFoundation and managing an AVCaptureSession on a sessionQueue:

private let sessionQueue = DispatchQueue(label: "com.andrewferrarone.sessionQueue")

在Apple文档中的很多代码示例中我看到了:

in a lot of code examples in the apple documentation I see this:

self.sessionQueue.async { [unowned self]
    //
}

这里需要 [无主自我] self吗? self(viewController)引用 self.sessionQueue 并将调度分派到 self.sessionQueue 捕获self。这是一个参考周期吗? self不引用闭包,只是DispatchQueue。如果 [unowned self] 是必要的,那么根据我的理解,我只想使用无主的自我如果我是确定自我不会是零。那么我可以说我在 sessionQueue 上放了一个任务需要很长时间才能弹出viewController并在任务完成之前解除分配? sessionQueue 和任务会发生什么?如果它仍然在那时,当它试图访问自己时,应用程序将崩溃。另一方面,因为无主的self不会增加self的保留计数,所以它不会阻止viewController被释放。

Is the [unowned self] self here necessary? self (the viewController) references self.sessionQueue and the closure dispatched to self.sessionQueue captures self. Is this a reference cycle? self is not referencing the closure, just the DispatchQueue. If [unowned self] is necessary, then from what I understand, I only want to use unowned self if I am certain that self will not be nil. So lets say I put a task on sessionQueue that takes a long time and the viewController gets popped off and is deallocated before the task finishes? What happens to sessionQueue and the task? If its still around then, when it tries to access self, the app will crash. On the other hand, since unowned self doesn't increment the retain count of self, then it won't prevent the viewController from being deallocated.

所以我的问题是什么当一个viewController被解除分配时会发生DispatchQueues,在这种情况下会发生什么情况,如果一个viewController在dispatchQueue任务完成之前被解除分配?如果有人能够对这里发生的事情有所了解,那将非常有帮助和赞赏。

So My question is what happens to DispatchQueues when a viewController is deallocated and what happens in this case, if a viewController gets deallocated before a dispatchQueue task is finished? If someone could shed some light on what all is going on here that would be very helpful and appreciated.

感谢帮助我的朋友们!

推荐答案


这里需要 [无主自我] self吗?

不仅不需要使用 [无主自我] ,在异步调度的块中它是非常危险的。你最终得到一个指向解除分配对象的悬空指针。

Not only is the use of [unowned self] not necessary, but it's very dangerous in an asynchronously dispatched block. You end up with a dangling pointer to a deallocated object.

如果你不想保持对 self 在异步调用中,请使用 [weak self] 。如果您知道在取消分配 self 之后永远不能调用块,则应该只使用 unowned 。显然,使用异步调用时,您不知道这一点,因此不应在该上下文中使用 [unowned self]

If you don't want to keep keep a strong reference to self in an asynchronous call, use [weak self], instead. You should only use unowned if you know the block can never be called after self is deallocated. Obviously, with async call, you don't know this, so [unowned self] should not be used in that context.

您是否使用 [弱自我] 或使用强引用是一个问题,您是否需要异步执行的块来保持对相关对象的强引用或不。例如,如果您只更新视图控制器的视图控件,那么 [弱自我] 就可以了(更新已被解除的视图没有任何意义)。

Whether you use [weak self] or use strong references is a question of whether you need the asynchronously executed block to keep a strong reference to the object in question or not. For example, if you're updating a view controller's view's controls only, then [weak self] is fine (no point in updating a view that has been dismissed).

无主引用更为关键的用途是避免强烈的参考周期。但这并不适用于您提供的示例。如果视图控制器保留对块本身的一些引用(例如,你有一些闭包属性)并且那些闭包引用 self ,你只需要担心这些周期,但没有 / 无主限定符。

The more critical use of weak and unowned references is to avoid strong reference cycles. But that doesn't apply in the example you've provided. You only need to worry about those cycles if the view controller keeps some reference to the blocks itself (e.g. you have some closure property) and those closures reference self, but without a weak/unowned qualifier.


我的问题是当取消分配视图控制器时 DispatchQueue 会发生什么?

这些队列将继续存在,任何调度的块都将继续存在,直到(a)所有调度的块完成; (b)没有更强烈的队列引用。

Those queues will continue to exist, as will any dispatched blocks, until (a) all dispatched blocks finish; and (b) there are no more strong references to the queue.

因此,如果您使用异步调度块 self (即视图控制器),它们将在视图控制器释放后继续运行。这就是为什么在这种情况下不使用无主至关重要。

So if you asynchronously dispatch blocks with weak references to self (i.e. the view controller), they will continue to run after the view controller is released. This is why it's critical to not use unowned in this context.

对于它的价值,经验测试可能是有启发性的。考虑:

For what it's worth, empirical tests can be illuminating. Consider:

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")
    }

}

如果在调度的块排队并运行时关闭此视图控制器,您将看到:

If you dismiss this view controller while the dispatched blocks are queued up and running, you'll see:


  • 使用 [弱自我] ,视图控制器仅保留到当前调度块结束,视图然后将释放控制器,并且t其余的块会迅速关闭,但由于 [弱自我] performSomeTask 将无法运行取消视图控制器后。

  • With [weak self], the view controller is retained only until the current dispatched block finishes, the view controller will then be released, and the rest of the blocks will rapidly fire off, but because of [weak self], the performSomeTask won't run after the view controller is dismissed.

如果用替换 weak (显然在 self?.performSomeTask(...)中删除​​如果在排队的块有机会启动之前关闭视图控制器,你会看到它崩溃。这说明了为什么 [unowned self] 使用异步代码是如此危险。

If you replace weak with unowned (and obviously remove the ? in self?.performSomeTask(...)), you'll see it crash if you dismiss the view controller before the queued blocks have had a chance to start. This is illustrative of why [unowned self] is so dangerous with asynchronous code.

如果你只是完全删除 [弱自我] 并让它使用对 self 的隐式强引用,你会看到它赢了' t取消分配视图控制器,直到所有排队的块完成。

If you simply remove [weak self] altogether and let it use a implicitly strong reference to self, you'll see it won't deallocate the view controller until all queued blocks finish.

这篇关于当UIViewController被取消分配时,Dispatch Queues会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆