简体   繁体   中英

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

I know that you have to balance out the calls with DispatchGroup for both .enter() and .leave() .

The question is if I started a dispatchGroup.enter() and I dismissed/popped the vc before the calls were balanced, would the app crash? Basically, would deinit() change the outcome because the vc is no longer in memory?

eg. This starts, but before the 3rd background task is completed, the vc is dismissed or popped. .leave() only ran twice but it's supposed to run 3 times. This is just a simple example to get the idea across:

func viewDidLoad()

    let group = DispatchGroup()

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

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

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

No, failing to call leave will not, itself, cause a crash. (It likely is not relevant here, but calling leave too many times will crash.)

What will happen, though, is that until all of the enter calls are offset by leave calls, the dispatch group will not be released. Worse, anything captured strongly by the completion handler and the notify closures will not get released. So you really do want to ensure that all enter calls are eventually offset by leave calls.

But I would first suggest confirming that leave is not getting called enough times. Typically the exact opposite problem occurs, that leave is called the correct number of times, but that one or more of these background tasks finish after the view controller was dismissed, and does not handle this scenario gracefully.


For what it is worth, if someBackgroundTask is doing something that is no longer needed after the view controller is dismissed, we would:

  • make someBackgroundTask a cancelable task, if possible;

  • make sure the various closures do not maintain a strong reference back to the view controller (by using [weak self] pattern), eliminating strong reference cycles;

  • make sure the closure gracefully handles if the view controller is deallocated by the time the closure runs, eg

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

    and

  • in deinit of the view controller (or somewhere equivalent) cancel the tasks that are no longer needed (again, assuming it is a cancelable task).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM