Converting Completion with a return to async await

How do I convert a function that has a completion handler and a return statement into an async await function?

func viewController(completion: (string: String) -> Void) -> NewController{
 NewViewController(
			completion: { text in
				completion(text)
			})
}

If the function has both a synchronous return and an asynchronous completion handler, then there's not a straightforward conversion to an async function. Because you (presumably) need the synchronous result immediately, you don't want to await for the completion handler.

In a case like that, you might consider returning a tuple of the return value and the Task that's running the async code.

// Before
func test1(completion: @escaping (String)->Void) -> Int {
    DispatchQueue.global().async {
        completion("hi")
    }
    return 42
}

// After
func test1() -> (Int, Task<String,Never>) {
    let task = Task {
        return "Hi"
    }

    return (42, task)
}

// Later, when using it…
let (integer, task) = task1()
print("I'm using the integer \(integer) right away")

// And now suspend and wait for the value
let string = await task.value

HOWEVER, this situation doesn't actually match the code you showed in your initial post. In the initial post, the completion handler is not actually invoked by this function; it's just passed off to the view controller, and the view controller will presumably be responsible for invoking the completion handler at some future point after the view controller is displayed. If that's reflective of your actual use case, then there's actually no need to convert this to an async function, because it's not actually waiting for a completion handler at all. (Unless the view controller is calling the completion handler from within its init method, I suppose.)

2 Likes

Yeah its returning a view controller. The colsures injected will only be used later