How to resume a continuation ensuring that the result is delivered on the MainActor?

1.4k Views Asked by At

I have a continuation:

func a() async -> Int {
    await withCheckedContinuation { continuation in
        continuation.resume(returning: 3)
    }
}

I would like all callers of this function to receive the result on the MainActor. I wouldn't like the caller to have to explicitly specify this rescheduling. I don't want this:

func c() async {
    let three = await a()
    await MainActor.run {
        b(three)
    }
}

What I instead want is for the entire code after returning to be performed on the MainThread until the next suspension point, something like this:

func c1() async {
    let three = await a()

    b(three) // Guaranteed main thread, although nothing speaks of it here
}

In a way, I want a to declare that I return only on main actor!, like this:

func a() @MainActor async -> Int {
    await withCheckedContinuation { continuation in
        continuation.resume(returning: 3)
    }
}

Is there any way to even do this?

UPDATE: Both commenters have suggested that I annotate the enclosing functions c and c1 with @MainActor.

@MainActor
func c() async {
    let three = await a()
    await MainActor.run {
       b(three)
    }
}

This doesn't do it like I need it. It says:

  • every time I await somebody, they must return on the main thread

But what I need instead is this:

  • every time somebody awaits me, they must get my result on the main thread
2

There are 2 best solutions below

0
On BEST ANSWER

No, there is no way to do this.

If you await some function, you can decide on which thread will it return. But being an await-able function, you can not make sure that your result will be delivered to the caller on a particular and/or main thread.

1
On

It should be possible like this:

func a() async -> Int {
    await withCheckedContinuation { continuation in
        Task {@MainActor in
            continuation.resume(returning: 3)
        }
    }
}