iOS - Swift - Function that returns asynchronously retrieved value
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A Swift function cannot synchronously return a value that has not arrived yet from asynchronous work such as a network request. The real solution is to change the API shape: use a completion handler or make the function itself async so the caller waits correctly.
Why a Direct Return Does Not Work
This is the mistake people usually try first:
The function returns before the network callback runs, so result is returned too early. That is not a Swift quirk. It is the normal behavior of asynchronous execution.
Completion Handler Approach
A traditional fix is to return through a closure.
Caller side:
This makes the asynchronous nature explicit instead of pretending the value is immediately available.
async and await Approach
Modern Swift concurrency gives a cleaner syntax for the same idea.
Caller side:
This still is not synchronous. It simply makes asynchronous code read more clearly.
Update the UI on the Main Actor
If the asynchronously retrieved value updates UI state, make sure the UI work happens on the main actor.
The networking can happen asynchronously, but UI updates must still follow UIKit rules.
Design the API Around Timing
The core design principle is simple: a function should advertise whether it produces a value now or later.
Use:
- A direct return value for immediately available data.
- A completion handler for callback-style asynchronous work.
- '
asyncfor modern structured concurrency.'
Trying to hide delayed work behind a direct synchronous return almost always creates bugs.
Legacy APIs Can Be Wrapped
If you are stuck with a completion-handler API, you do not need to rewrite the whole networking layer at once. You can bridge older callbacks into async functions gradually and keep the call sites cleaner over time.
Common Pitfalls
- Trying to return a value before the asynchronous callback has run.
- Mixing completion handlers and synchronous return values in the same design.
- Forgetting to propagate errors from asynchronous work.
- Updating UIKit state from the wrong execution context.
- Treating
asyncas magic synchronous behavior rather than as explicit suspension.
Summary
- A function cannot synchronously return a value that will only exist later.
- Use a completion handler or an
asyncfunction instead. - The caller must also participate in the asynchronous flow.
- Keep UI updates on the main actor.
- The right fix is to redesign the API around the timing of the data, not to fight the timing model.

