MainActor vs MainActor(unsafe)
Asked Answered
A

1

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?

As answered 13/12, 2021 at 12:13 Comment(0)
T
6

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.

Thorlay answered 21/8, 2022 at 15:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.