How to deal with application termination/teardown/deinit with Swift Concurrency?

My Cocoa application wants to disconnect a network client before quitting. Seems pretty straightforward, but the operation is async throws.

So far, I have this to handle termination:

  @MainActor func applicationWillTerminate(_: Notification) {
    Task {
      try! await viewController.tearDownClient()
    }
  }

This doesn't actually work because the Task gets scheduled to run later. The application is currently about to terminate, so there is no "later" for the Task to run in.

I have run into a similar situation with the actual view controller itself:

  deinit {
    Task {
      try! await tearDownClient()
    }
  }

This doesn't work for similar reasons.

I suppose what I need is a way to block on the completion of these asynchronous operations. I realize that is an undesired operation most of the time, but I don't see another way.

Assuming we're talking about NSApplicationDelegate, then use applicationShouldTerminate(_:) to control the behavior.

1 Like

Thank you, I didn't know about this! Just patched my app to advantage of this and now all's well—clients terminate when quitting the app.

I am still curious about tearing down the network client in deinit, although that is less important to me.

Thinking about it, though, deinit seems fundamentally incompatible with concurrency. deinit should really be a one-shot, synchronous operation, and wanting to kick off an operation that could possibly involve switching between tasks in a thread pool feels analogous to wanting to fit a square peg into a round hole.

Terms of Service

Privacy Policy

Cookie Policy