在 DispatchGroup 完成之前关闭 vc 会使应用程序崩溃吗?

Will dismissing a vc before a DispatchGroup finishes crash the app?

我知道您必须平衡 DispatchGroup.enter().leave() 的调用。

问题是,如果我在调用平衡之前启动 dispatchGroup.enter()dismissed/popped vc,应用程序会崩溃吗?基本上,deinit() 会因为 vc 不在内存中而改变结果吗?

例如。这开始了,但在第 3 个后台任务完成之前,vc 被关闭或弹出。 .leave() 只 运行 两次,但应该 运行 3 次。这只是一个简单的例子来理解这个想法:

func viewDidLoad()

    let group = DispatchGroup()

    // there are 3 background tasks
    for task in backgroundTasks {

        group.enter()
        someBackgroundTask(... completion: { (_) in

            group.leave()
        })
    }
    group.notify...
}

不,调用 leave 失败本身不会导致崩溃。 (这里可能不相关,但调用 leave 太多次会崩溃。)

不过,在所有 enter 调用都被 leave 调用抵消之前,调度组不会被释放。更糟糕的是,完成处理程序和 notify 闭包强烈捕获的任何内容都不会被释放。因此,您确实希望确保所有 enter 调用最终都被 leave 调用所抵消。

但我首先建议确认 leave 没有被调用足够的次数。通常会出现完全相反的问题,leave 被调用了正确的次数,但是这些后台任务中的一个或多个在视图控制器被关闭后完成,并且确实不能优雅地处理这种情况。


对于它的价值,如果 someBackgroundTask 正在做一些在视图控制器被关闭后不再需要的事情,我们会:

  • 尽可能将 someBackgroundTask 设为可取消的任务;

  • 确保各种闭包不维护对视图控制器的强引用(通过使用[weak self]模式),消除强引用循环;

  • 如果视图控制器在闭包运行时被释放,请确保闭包能够正常处理,例如

    group.notify(queue: .main) { [weak self] in
        guard let self = self else { return }
    
        ...
    }
    

  • 在视图控制器的 deinit 中(或等效的地方)取消不再需要的任务(同样,假设它是一个可取消的任务)。