Damiano Curia
Damiano Curia

Reputation: 175

Sync closure needs to wait for async code

I am developing an app that uses MPRemoteCommandCenter to control audio reproduction from the lock screen.

The code is inside a @MainActor view-model, part of a SwiftUI project.

The initial code that I need to incorporate is:

            commandCenter.playCommand.isEnabled = true
            commandCenter.playCommand.addTarget { [unowned self] event in
                    if !self.isPlaying {
                        self.playOrPause()
                        return .success
                    }
                    return .commandFailed
            }

I have tried this:

            commandCenter.playCommand.isEnabled = true
            commandCenter.playCommand.addTarget { [unowned self] event in
                return await MainActor.run {
                    if !self.isPlaying {
                        self.playOrPause()
                        return .success
                    }
                    return .commandFailed
                }
            }

But still it doesn't compile.

I understand why: the callback method is not marked to be async. Still it expects a value, that I can return only from async code, because I need to wait to re-enter into the main thread.

Can anyone please help me?

Upvotes: 1

Views: 1630

Answers (1)

HunterLion
HunterLion

Reputation: 4026

You cannot ask for a sync function to wait for an async. You can have however an async function receiving the returned values from other async closures using withCheckedContinuation().

In your case, this is how it might work:

        let isSuccessfullyCompleted: Bool = await withCheckedContinuation { continuation in

            commandCenter.playCommand.isEnabled = true
            commandCenter.playCommand.addTarget { [unowned self] event in
                    if !self.isPlaying {
                        self.playOrPause()
                        continuation.resume(returning: true)
                    } else {
                        continuation.resume(returning: false)
                    }
            }        
        }

With the code above, isSuccessfullyCompleted will wait for the closure to complete and return a value, before resuming the code. The variable doesn't need to be a Bool, but the code above needs to run in an async function.

Upvotes: 1

Related Questions