为什么在deinit后dispatchqueue.global()仍然有效

时间:2020-06-27 15:40:57

标签: swift grand-central-dispatch

deinit {
    print("deinit")
}

DispatchQueue.global().async { [weak self] in
            
    while(true){
        print(self)
        print("sleep")
        sleep(1)
    }
}

尽管在课堂上被称为deinitDispatchQueue.global()中的无限循环仍然有效。

在这种情况下,例如,

可选(

睡觉

可选(

睡觉

取消初始化(在取消初始化之后)

睡觉

睡觉

...(重复)


如果有人教我为什么,我将非常感谢

3 个答案:

答案 0 :(得分:2)

全局调度队列不在应用程序的类中。它在系统中。您已经启动了一个独立线程,并且该线程一直运行直到其操作结束为止,在这种情况下,它永远不会运行。这与您的类是否获得deinit和实例不再存在无关。

实际上,一个常见的错误是启动一个独立线程,一段时间后,引用了您的实例。如果同时调用了您的实例deinit,则可能发生各种可怕的事情,从崩溃到deinit之后实例一直处于不确定状态都可以发生。

但是,这不是在这里发生;您已经正确使用了weak self,因此您的实例确实已经按照nil的说明以良好的顺序消失了。因此,您所看到的是预期的行为,尽管显然这在现实生活中并不是一件好事。

答案 1 :(得分:1)

GCD独立于对象的生命周期管理队列(以及分配给这些队列的任务)。

FWIW,您正在使用全局队列这一事实与手头的问题无关。使用自定义调度队列(或操作队列)会产生完全相同的行为:

let queue = DispatchQueue(label: "private_queue")
queue.async { [weak self] in
    while true {
        print(self)
        print("sleep")
        sleep(1)
    }
}

除非您明确退出循环(使用while测试,或者如果要手动取消,使用{{ 3}})。

GCD不执行抢先取消。


注意,此调度任务当前正在运行甚至不相关。所分配的任务是否已完成才很重要。 self == nil循环无关紧要。考虑:

while

这会将100个任务排入该自定义串行队列。但是,如果let queue = DispatchQueue(label: "private_queue") for i in 0 ..< 100 { queue.async { [weak self] in print("iteration \(i) queued by \(self)") Thread.sleep(forTimeInterval: 1) } } print("done dispatching") 在所有这些任务完成之前被释放,则此队列将继续处理这100个已分派的任务。

最重要的是,尽管我们可以谈论GCD对全局队列的管理,但这并不是一个突出的问题。关键观察结果是:

  • 添加到调度队列中的任务(或添加到操作队列中的操作)有效地保持对其各自队列的强引用;

  • 已分派的工作项(或操作)将继续执行,而不管排队它的对象可能已被释放的事实(当然,除非您测试self);和

  • 即使已分派的任务(或操作)尚未开始,它也将保留在该队列中,直到完成执行(或您手动取消它)为止...再一次,与进入队列的对象是否无关紧要它是否已被释放。

答案 2 :(得分:0)

DispatchQueue.global()返回全局系统队列。 https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global

GCD管理一个共享线程池,确定并向全局调度队列添加代码块以执行该代码。

在“调试内存图”中,您可以找出许多活跃的调度队列 enter image description here

您在调度队列上执行的执行与DialogFlowPopUpController实例的 deinit

不相关
// your execution should not be completed because there are no break statement
{ [weak self] in
    while(true){
        print(self)
        print("sleep")
        sleep(1)
    }
}

如何更改执行以打破无限循环

DispatchQueue.global().async { [weak self] in
    while(self != nil){
        print(self)
        print("sleep")
        sleep(1)
    }
}