DispatchQueue's closure is @Sendable, how can it access main actor isolated values?

17 hours ago 1
ARTICLE AD BOX

DispatchQueue.main.async is just a special case hardcoded into the compiler. This is checked by the function isMainDispatchQueueMember, which simply looks at the AST to see if it matches "DispatchQueue.main". If it does, the compiler would eventually adjust the closure's type to be main actor isolated, thereby making the closure sendable.

You can follow the compiler's source code from this line to see how it eventually reaches applyUnsafeConcurrencyToParameterType.

Because this is only an AST check, writing DispatchQueue.main in different but equivalent ways will cause the check to fail and produce warnings/errors like you expected.

let queue = DispatchQueue.main queue.async { mainActorFunc() // warning } typealias DP = DispatchQueue DP.main.async { mainActorFunc() // warning }

On the flip side, if you make your own type named DispatchQueue and give it a main property and async method, there will be no warnings at all!

struct DispatchQueue { static let main = DispatchQueue() func async(block: @Sendable () -> Void) { } } DispatchQueue.main.async { mainActorFunc() // totally fine by the compiler }

See also: https://oleb.net/2024/dispatchqueue-mainactor/

Sweeper's user avatar

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Read Entire Article