0Pricing
Swift Academy · Lesson

Bridging legacy callbacks/Combine to async/await

Wrap completion-handlers using withCheckedContinuation / withCheckedThrowingContinuation and bridge Combine publishers into AsyncSequence for simple for await loops.

Why bridge?

Goal: Use continuations to wrap callbacks and treat Combine streams as AsyncSequence.

  • Continuations (non-throwing / throwing)
  • URLSession bridging example
  • Combine → for await consumption

Non-throwing continuation

Use withCheckedContinuation when the legacy API cannot fail. Resume exactly once.

// Old-style API
func fetchName(completion: @escaping (String) -> Void) {
    // simulate async
    Task { try? await Task.sleep(nanoseconds: 80_000_000); completion("Ana") }
}

// Async wrapper using continuation (non-throwing)
func fetchName() async -> String {
    await withCheckedContinuation { (cont: CheckedContinuation<String, Never>) in
        fetchName { value in cont.resume(returning: value) }
    }
}

Task {
    let name = await fetchName()
    print("name:", name) // "Ana"
}

All lessons in this course

  1. Producer/consumer, pipelines, timeouts
  2. Bridging legacy callbacks/Combine to async/await
  3. Testing async code (XCTest)
← Back to Swift Academy