Conectar callbacks heredados/Combine con async/await
Envuelva los completion handlers con withCheckedContinuation / withCheckedThrowingContinuation y conecte los publishers de Combine con AsyncSequence para usar bucles sencillos de for await .
Conectar callbacks heredados/Combine con async/await es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 2 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 3 lecciones en total.
¿Por qué crear puentes?
Objetivo: Use continuaciones para envolver callbacks y trate los flujos de Combine como AsyncSequence.
- Continuaciones (sin lanzar errores / que lanzan errores)
- Ejemplo de puente con URLSession
- Consumo de Combine →
for await
Continuación sin errores
Use withCheckedContinuation cuando la API heredada no pueda fallar. Reanude exactamente una vez.
// 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"
}Continuación que lanza errores
Use withCheckedThrowingContinuation para exponer los errores heredados mediante throw. Asegúrese de que haya una única ruta de reanudación.
enum NetError: Error { case offline; case badStatus }
func loadNumber(completion: @escaping (Result<Int, Error>) -> Void) {
Task {
try? await Task.sleep(nanoseconds: 80_000_000)
completion(.failure(NetError.offline))
}
}
func loadNumber() async throws -> Int {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Int, Error>) in
loadNumber { result in
switch result {
case .success(let v): cont.resume(returning: v)
case .failure(let e): cont.resume(throwing: e)
}
}
}
}
Task {
do {
let n = try await loadNumber()
print(n)
} catch {
print("error:", error) // offline
}
}Puente con URLSession
Envuelva las API basadas en completion handler (por ejemplo, URLSession) para obtener una función limpia async throws. Recuerde reanudar exactamente una vez.
import Foundation
func getText(from url: URL) async throws -> String {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<String, Error>) in
let task = URLSession.shared.dataTask(with: url) { data, resp, err in
if let err = err { cont.resume(throwing: err); return }
guard let data = data, let text = String(data: data, encoding: .utf8) else {
cont.resume(throwing: URLError(.badServerResponse)); return
}
cont.resume(returning: text)
}
task.resume()
}
}
// Demo (works in environments with network access)
let demoURL = URL(string: "https://example.com")!
Task {
do { let body = try await getText(from: demoURL); print(body.prefix(15)) }
catch { print("network error:", error) }
}Combine como AsyncSequence
Muchos publishers de Combine exponen .values, lo que permite recorrer las emisiones con for await sin crear puentes personalizados.
import Combine
import Foundation
let subject = PassthroughSubject<Int, Never>()
// Consume Combine as AsyncSequence:
Task {
var produced: [Int] = []
for await value in subject.values { // Publisher.values -> AsyncSequence
produced.append(value)
if produced.count == 3 { break } // stop after 3 values
}
print("collected:", produced) // e.g., [1,2,3]
}
// Publish a few values
var cancellables = Set<AnyCancellable>()
Timer.publish(every: 0.05, on: .main, in: .common)
.autoconnect()
.prefix(3)
.scan(0) { acc, _ in acc + 1 }
.sink { subject.send($0) }
.store(in: &cancellables)Publisher → AsyncStream
Si .values no está disponible, cree un pequeño puente mediante AsyncStream. No olvide cancelar la suscripción cuando termine.
import Combine
// Bridge ANY Publisher to AsyncSequence using AsyncStream (simple version)
extension Publisher {
func asAsyncStream() -> AsyncStream<Output> {
AsyncStream { continuation in
let cancel = self.sink(
receiveCompletion: { _ in continuation.finish() },
receiveValue: { value in continuation.yield(value) }
)
continuation.onTermination = { _ in cancel.cancel() }
}
}
}
// Demo:
let pub = [10, 20, 30].publisher
Task {
var sum = 0
for await v in pub.asAsyncStream() { sum += v }
print("sum:", sum) // 60
}Usar una continuación que lanza errores
Comprobación rápida: ¿Cuál es la mejor forma de convertir un callback que puede fallar en código async?
Repaso
Repaso: Envuelva los callbacks heredados con continuaciones (que lancen errores o no) y consuma Combine mediante .values o un pequeño puente con AsyncStream. Mantenga una sola reanudación y cancele las suscripciones al finalizar.
Preguntas frecuentes
¿La lección «Conectar callbacks heredados/Combine con async/await» es gratis?
Sí — el texto completo de «Conectar callbacks heredados/Combine con async/await» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 3 lecciones en total.
¿Qué aprenderé en «Conectar callbacks heredados/Combine con async/await»?
Envuelva los completion handlers con withCheckedContinuation / withCheckedThrowingContinuation y conecte los publishers de Combine con AsyncSequence para usar bucles sencillos de for await . Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Swift Academy?
No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 3.
¿Cuánto tiempo toma la lección «Conectar callbacks heredados/Combine con async/await»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Swift Academy?
Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Productor/consumidor, canalizaciones y tiempos de espera
- Conectar callbacks heredados/Combine con async/await
- Probar código async (XCTest)