From async/await back to closure based sync func with completion

Hey,

I cannot find a good example how to deal with the problem that I would like to solve.
I understand that I can call an async/await function from the sync function using Task, Task.detached, MainActor.run... .

But can I call the callback function from the async task back to synchronous function.
This is my sudo code problem to solve.

    static func makeRow(client: HTTPClient, completion: @escaping (Row?) -> Void) {
        Task {
            guard let rowData = await loader.loadData() else {
                completion(nil)
                return
            }

            let row = Row { tableViewCell in // <- cannot pass function of type '(UITableViewCell) async -> Void' to parameter expecting synchronous function type
                tableViewCell.text = rowData.title
            }

            completion(row)
        }
    }

The reason why I do this is I'm making a framework where internally I would like to start using async/await but I don't want to force/expose it yet to the rest of my team.

Yes, using a continuation. Look for withCheckedContinuation.

1 Like

I'm not sure if I made it clear.
I don't want to convert makeRow to be an async function like

static func makeRow(client: HTTPClient) async -> Row? { ... }

I want to keep the declaration as it is.
I want to use inside the async loadData().
I want to initialize the Row type which has the constructor that takes a closure

init(configure: @escaping (UITableViewCell) -> Void) { }

which would require to run the content of it on the main thread as this is UI related.
In the end, I want to call the makeRow's method completion handler with the configured Row instance.

Oh, yes, sorry. This direction is even easier: just make a task and have it call the completion handler as the last thing it does.

Yes, correct this is what I try. I problem that I have is the inner closure passed to the Row constructor makes calls and uses UI-related properties. Because of it I get those errors

property 'parentViewController' isolated to global actor 'MainActor' can not be referenced from a non-isolated synchronous context
call to main actor-isolated instance method 'set(data: rowData)' in a synchronous nonisolated context

Okay. So you need to mark that function as @MainActor in the declaration of the Row initializer.

1 Like