Async functions declaration in Swift - Time & Space Complexity
When we declare async functions, we want to know how their execution time changes as we call them with different inputs.
We ask: how does the time to complete grow when the input size grows?
Analyze the time complexity of the following async function declaration and usage.
func fetchData(for ids: [Int]) async -> [String] {
var results = [String]()
for id in ids {
let data = await fetchSingleData(id: id)
results.append(data)
}
return results
}
func fetchSingleData(id: Int) async -> String {
// Simulates network call
return "Data for \(id)"
}
This code fetches data asynchronously for each id in the input list one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop that calls
fetchSingleDatafor each id. - How many times: Once for each element in the input array
ids.
Each id causes one async call, so the total work grows as the number of ids grows.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 async calls |
| 100 | 100 async calls |
| 1000 | 1000 async calls |
Pattern observation: The total time grows roughly in direct proportion to the number of items.
Time Complexity: O(n)
This means the time to finish grows linearly with the number of items you fetch.
[X] Wrong: "Async functions always run instantly or in constant time."
[OK] Correct: Even though async functions let other work happen while waiting, the total time still depends on how many times you call them and what each call does.
Understanding how async functions scale with input size helps you write efficient code and explain your reasoning clearly in real projects or interviews.
What if we changed the for-loop to run all fetches concurrently using async let? How would the time complexity change?