5

We can create a @MainActor Task like this:

Task { @MainActor in
    print("hi")
}

But also with @MainActor(unsafe) like this:

Task { @MainActor(unsafe) in
    print("hi")
}

What's the difference between these two methods?

George
  • 25,988
  • 10
  • 79
  • 133

1 Answers1

4

The main purpose of @MainActor(unsafe) is to make incremental adoption of concurrency easier. You can read this in detail explained in the proposal. If you mark your type as @MainActor(unsafe) if you try to access properties and methods synchronously in code that hasn't adopted async/await without breaking anything.

For example following code won't compile with only @MainActor as here actor isolated property accessed from synchronous context:

@MainActor
class SomeViewModel {
    let value1 = 0
    var value2 = 0
    func getValue2() -> Int { value2 }
    func setValue2(_ newValue: Int) { value2 = newValue }
}

func doSomething(with viewModel: SomeViewModel) {
    _ = viewModel.value1
    _ = viewModel.value2 // ERROR: Property 'value2' isolated to global actor 'MainActor' can not be referenced from this synchronous context
    _ = viewModel.getValue2() // ERROR: Call to main actor-isolated instance method 'getValue2()' in a synchronous nonisolated context
    viewModel.setValue2(3) // ERROR: Call to main actor-isolated instance method 'setValue2' in a synchronous nonisolated context
}

But if you change @MainActor to @MainActor(unsafe) there are no more build errors. Note that @MainActor(unsafe) is only applicable to swift 5 code to make incremental adoption of concurrency easier and in swift 6 it won't have any effect and would behave the same as @MainActor.

Also @MainActor(unsafe) is interchangeable with @preconcurrency @MainActor. You also can use -warn-concurrency compiler option to get all the errors that you would get with only @MainActor as warnings.

Soumya Mahunt
  • 2,148
  • 12
  • 30