SwiftUI.View Compiler Errors when Property Wrapper is Annotated with MainActor

Hi! I'm seeing some confusing behavior with a propertyWrapper that tries to constrain its wrappedValue to MainActor. I'm using this in a SwiftUI.View… but I'm seeing some confusing behavior when I try to add that component to my graph. There seems to be some specific problem when body is defined in an extension.

I start with a simple property wrapper:

@propertyWrapper struct Wrapper<T> {
  @MainActor var wrappedValue: T
}

I then try a simple App with a View that uses a Wrapper:

@main struct MainActorDemoApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

struct ContentView: View {
  @Wrapper var value = "Hello, world!"
  
  var body: some View {
    Text(self.value)
  }
}

This code compiles with no problems for me.

For style… I might choose to define the body property of my MainActorDemoApp with an extension:

@main struct MainActorDemoApp: App {
//  var body: some Scene {
//    WindowGroup {
//      ContentView()
//    }
//  }
}

extension MainActorDemoApp {
  var body: some Scene {
    WindowGroup {
      ContentView() //  Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context
    }
  }
}

struct ContentView: View {
  @Wrapper var value = "Hello, world!"
  
  var body: some View {
    Text(self.value)
  }
}

Explicitly marking my body as a MainActor fixes the compiler error:

@main struct MainActorDemoApp: App {
//  var body: some Scene {
//    WindowGroup {
//      ContentView()
//    }
//  }
}

extension MainActorDemoApp {
  @MainActor var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

struct ContentView: View {
  @Wrapper var value = "Hello, world!"
  
  var body: some View {
    Text(self.value)
  }
}

So I guess the question is… why? Why would code that breaks when my body is in an extension not break when my body is in my original struct definition? Is this intended behavior?

I'm on Xcode Version 15.2 (15C500b) and Swift 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5).

It's unclear to me what is "wrong" about the code that broke… any ideas?

Replies

I can also fix the compiler error by putting the App conformance directly on the extension where my body is defined:

@main struct MainActorDemoApp {
//  var body: some Scene {
//    WindowGroup {
//      ContentView()
//    }
//  }
}

extension MainActorDemoApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

struct ContentView: View {
  @Wrapper var value = "Hello, world!"
  
  var body: some View {
    Text(self.value)
  }
}

I found this article quite enlightening: https://lucasvandongen.dev/swift_actors_and_protocol_extensions.php

I found this article quite enlightening: https://lucasvandongen.dev/swift_actors_and_protocol_extensions.php

@enodev I'll take a look. Thanks!