Search code examples
swiftswift-concurrency

Difference between starting a detached task and calling a nonisolated func in main actor


Imagine I'm in a class annotated with @MainActor so that all the functions are tied to the main actor. I'm trying to understand what the difference is between doing the following:

func bar() {
  Task.detached(priority: .background) {
    await foo()
  }
}

func foo() async {
  ...
}

vs

func bar() {
  Task(priority: .background) {
    await foo()
  }
}

nonisolated func foo() async {
  ...
}

Are they the same?


Solution

  • You said:

    Imagine I'm in a class annotated with @MainActor so that all the functions are tied to the main actor. I'm trying to understand what the difference is between doing the following:

    func bar() {
      Task.detached(priority: .background) {
        await foo()
      }
    }
    
    func foo() async {
      ...
    }
    

    The bar method creates a non-structured task, which, because it is a detached task, is not on the current actor. But that task will await the foo method, which will run on the main actor. The fact that foo is in a class bearing the @MainActor designation means that it is isolated to that actor, regardless of which Swift concurrency context you invoke it.

    But, in this case, there is little point in launching a detached task that only awaits an actor-isolated function.

    You continue:

    vs

    func bar() {
      Task(priority: .background) {
        await foo()
      }
    }
    
    nonisolated func foo() async {
      ...
    }
    

    In this case, bar will launch a task on the current (main) actor, but it will await the result of foo, which is nonisolated (i.e., not isolated to the main actor).

    So, the difference is that the first example, foo is actor-isolated, but it is not in the second example.