# Where View.task gets its main-actor isolation from

DevFeed: [Where View.task gets its main-actor isolation from](<https://devfeed.tech/articles/where-view-task-gets-its-main-actor-isolation-from-21715.md>)

Original publisher: [Read original article](<https://oleb.net/2022/swiftui-task-mainactor/>)

Author: Ole Begemann

Published: 2022-10-11T16:41:34Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [Swift](<https://devfeed.tech/topics/swift.md>), [context](<https://devfeed.tech/topics/context.md>), [interfaces](<https://devfeed.tech/topics/interfaces.md>), [modules](<https://devfeed.tech/topics/modules.md>)

Tags: [context](<https://devfeed.tech/tags/context.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [modules](<https://devfeed.tech/tags/modules.md>), [swift](<https://devfeed.tech/tags/swift.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

## AI overview

This article explains how SwiftUI's .task modifier inherits actor context from its use site. Calls inside a View body run on the main actor because View.body is annotated with @MainActor, while calls from nonisolated helper properties or functions run in the cooperative thread pool. It examines SwiftUI's hidden annotations and module interface declarations to explain the behavior.

## Source excerpt

SwiftUI's .task modifier inherits its actor context from the surrounding function. If you call .task inside a view's body property, the async operation will run on the main actor because View.body is (semi-secretly) annotated with @MainActor. However, if you call .task from a helper property or function that isn't @MainActor-annotated, the async operation will run in the cooperative thread pool. Example Here's an example. Notice the two .task modifiers in body and helperView. The code is identical in both, yet only one of them compiles -- in helperView, the call to a main-actor-isolated function fails because we're not on the main actor in that context: We can call a main-actor-isolated function from inside body, but not from a helper property. import SwiftUI @MainActor func onMainActor() { print("on MainActor") } struct ContentView: View { var body: some View { VStack { helperView Text("in body") .task { // We can call a @MainActor func without await onMainActor() } } } var helperView: some View { Text("in helperView") .task { // ❗ Error: Expression is 'async' but is not marked with 'await' onMainActor() } } } Why does it work like this? This behavior is caused by two (semi-)hidden annotations in the SwiftUI framework: The View protocol annotates its body property with @MainActor. This transfers to all conforming types. View.task annotates its action parameter with @_inheritActorContext, causing it to adopt the actor context from its use site. Sadly, none of these annotations are visible in the SwiftUI documentation, making it very difficult to understand what's going on. The @MainActor annotation on View.body is present in Xcode's generated Swift interface for SwiftUI (Jump to Definition of View), but that feature doesn't work reliably for me, and as we'll see, it doesn't show the whole truth, either. View.body is annotated with @MainActor in Xcode's generated interface for SwiftUI. SwiftUI's module interface To really see the declarations the compiler sees, we ne