为什么 dispatchqueue.global() 在 deinit 之后还活着
why dispatchqueue.global() still alive after deinit
deinit {
print("deinit")
}
DispatchQueue.global().async { [weak self] in
while(true){
print(self)
print("sleep")
sleep(1)
}
}
虽然调用了class中的deinit
,
DispatchQueue.global()
中的无限循环仍然存在。
在那种情况下,例如,
Optional(<OutOfKiosk.DialogFlowPopUpController: 0x150116e00>)
sleep
Optional(<OutOfKiosk.DialogFlowPopUpController: 0x150116e00>)
sleep
deinit (after deinit)
nil
sleep
nil
sleep
...(repeat)
如果有人教我为什么,我将非常感激
全局调度队列不在您应用的 class 中。它在系统中。您已经启动了一个独立的线程,它只是保持 运行 直到它的操作结束,在这种情况下永远不会。这与您的 class 是否获得 deinit
并且实例不复存在完全无关。
的确,一个常见的错误是启动一个独立的线程,一段时间后,引用您的实例。如果您的实例同时调用了 deinit
,则可能会发生各种可怕的事情,从崩溃到在 deinit
.
之后让您的实例处于不确定状态。
然而,这里并没有发生这种情况;你已经正确地使用了 weak self
所以你的实例确实已经井然有序地消失了,正如 nil
告诉你的那样。所以你看到的是预期的行为,尽管在现实生活中显然这不是一件好事。
DispatchQueue.global() returns 全局系统队列。
https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global
GCD 管理一个共享线程池,决定并将代码块添加到全局调度队列中以执行它。
在Debug Memory Graph中,你可以找出许多活着的调度队列
您在调度队列上执行的执行与 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)
}
}
GCD 独立于对象的生命周期管理队列(以及分派到这些队列的任务)。
FWIW,您使用的是全局队列这一事实与手头的问题无关。使用自定义调度队列(或操作队列)会导致完全相同的行为:
let queue = DispatchQueue(label: "private_queue")
queue.async { [weak self] in
while true {
print(self)
print("sleep")
sleep(1)
}
}
分派的任务,无论队列如何,使用 while
循环将继续执行,除非您明确退出循环(使用 self == nil
测试,或者,如果您想手动取消,使用isCancelled
).
GCD 不执行抢先取消。
请注意,此调度任务当前 运行 甚至无关紧要。只关心分派的任务是否完成。 while
循环无关紧要。考虑:
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 个任务排入该自定义串行队列。但是如果 self
在所有这些任务完成之前被释放,这个队列将继续处理这 100 个已分派的任务。
归根结底,虽然我们可以讨论 GCD 对全局队列的管理,但这不是重点。主要观察结果是:
添加到调度队列的任务(或添加到操作队列的操作)有效地保持对其各自队列的强引用;
分派的工作项(或操作)将继续执行,而不管将其排队的对象可能已被释放(当然,除非您测试是否 self == nil
) ;和
即使一个派遣的任务(或操作)还没有开始,它会一直留在那个队列中直到它执行完(或者你手动取消它)...再一次,是否无关紧要排队它的对象是否已被释放。
deinit {
print("deinit")
}
DispatchQueue.global().async { [weak self] in
while(true){
print(self)
print("sleep")
sleep(1)
}
}
虽然调用了class中的deinit
,
DispatchQueue.global()
中的无限循环仍然存在。
在那种情况下,例如,
Optional(<OutOfKiosk.DialogFlowPopUpController: 0x150116e00>)
sleep
Optional(<OutOfKiosk.DialogFlowPopUpController: 0x150116e00>)
sleep
deinit (after deinit)
nil
sleep
nil
sleep
...(repeat)
如果有人教我为什么,我将非常感激
全局调度队列不在您应用的 class 中。它在系统中。您已经启动了一个独立的线程,它只是保持 运行 直到它的操作结束,在这种情况下永远不会。这与您的 class 是否获得 deinit
并且实例不复存在完全无关。
的确,一个常见的错误是启动一个独立的线程,一段时间后,引用您的实例。如果您的实例同时调用了 deinit
,则可能会发生各种可怕的事情,从崩溃到在 deinit
.
然而,这里并没有发生这种情况;你已经正确地使用了 weak self
所以你的实例确实已经井然有序地消失了,正如 nil
告诉你的那样。所以你看到的是预期的行为,尽管在现实生活中显然这不是一件好事。
DispatchQueue.global() returns 全局系统队列。 https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global
GCD 管理一个共享线程池,决定并将代码块添加到全局调度队列中以执行它。
在Debug Memory Graph中,你可以找出许多活着的调度队列
您在调度队列上执行的执行与 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)
}
}
GCD 独立于对象的生命周期管理队列(以及分派到这些队列的任务)。
FWIW,您使用的是全局队列这一事实与手头的问题无关。使用自定义调度队列(或操作队列)会导致完全相同的行为:
let queue = DispatchQueue(label: "private_queue")
queue.async { [weak self] in
while true {
print(self)
print("sleep")
sleep(1)
}
}
分派的任务,无论队列如何,使用 while
循环将继续执行,除非您明确退出循环(使用 self == nil
测试,或者,如果您想手动取消,使用isCancelled
).
GCD 不执行抢先取消。
请注意,此调度任务当前 运行 甚至无关紧要。只关心分派的任务是否完成。 while
循环无关紧要。考虑:
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 个任务排入该自定义串行队列。但是如果 self
在所有这些任务完成之前被释放,这个队列将继续处理这 100 个已分派的任务。
归根结底,虽然我们可以讨论 GCD 对全局队列的管理,但这不是重点。主要观察结果是:
添加到调度队列的任务(或添加到操作队列的操作)有效地保持对其各自队列的强引用;
分派的工作项(或操作)将继续执行,而不管将其排队的对象可能已被释放(当然,除非您测试是否
self == nil
) ;和即使一个派遣的任务(或操作)还没有开始,它会一直留在那个队列中直到它执行完(或者你手动取消它)...再一次,是否无关紧要排队它的对象是否已被释放。