Swift Academy · 강의

기존 콜백/Combine을 async/await로 연결하기

withCheckedContinuation / withCheckedThrowingContinuation 으로 완료 처리기를 감싸고, Combine 게시자를 AsyncSequence 로 연결해 간단한 for await 반복문에서 사용합니다.

레슨 2/38개 단계

기존 콜백/Combine을 async/await로 연결하기은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 3개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

연결이 필요한 이유

목표: 컨티뉴에이션을 사용해 콜백을 감싸고, Combine 스트림을 AsyncSequence로 다루십시오.

  • 컨티뉴에이션(오류를 던지지 않는 방식/오류를 던지는 방식)
  • URLSession 연결 예시
  • Combine에서 for await로 값 소비하기

오류를 던지지 않는 컨티뉴에이션

기존 API가 실패할 수 없을 때는 withCheckedContinuation을 사용하십시오. 정확히 한 번만 재개해야 합니다.

// 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"
}

오류를 던지는 컨티뉴에이션

withCheckedThrowingContinuation을 사용해 기존 API의 오류를 throw로 전달하십시오. 재개 경로가 하나뿐인지 확인하십시오.

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
    }
}

URLSession 연결

완료 핸들러 API(예: URLSession)를 감싸 깔끔한 비동기 오류 처리 함수를 만드십시오. 정확히 한 번만 재개해야 한다는 점을 기억하십시오.

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을 AsyncSequence로 사용하기

많은 Combine 퍼블리셔는 .values를 제공하므로, 사용자 지정 연결 코드 없이 방출된 값을 for await로 순회할 수 있습니다.

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)

퍼블리셔 → AsyncStream

.values를 사용할 수 없다면 AsyncStream으로 간단한 연결 코드를 만드십시오. 작업이 끝나면 구독을 cancel하는 것도 잊지 마십시오.

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
}

오류를 던지는 컨티뉴에이션 사용

간단 확인: 실패할 수 있는 콜백을 비동기 코드로 연결하는 가장 좋은 방법은 무엇인가요?

요약

요약: 기존 콜백을 컨티뉴에이션(오류를 던지는 방식 또는 그렇지 않은 방식)으로 감싸고, Combine은 .values나 작은 AsyncStream 연결 코드로 소비하십시오. 재개는 한 번만 수행하고, 완료 시 구독을 cancel하십시오.

무료로 시작

AI 튜터와 함께 Swift을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
122
레슨
409

자주 묻는 질문

“기존 콜백/Combine을 async/await로 연결하기” 강의는 무료인가요?

네 — “기존 콜백/Combine을 async/await로 연결하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

“기존 콜백/Combine을 async/await로 연결하기”에서 뭘 배우나요?

withCheckedContinuation / withCheckedThrowingContinuation 으로 완료 처리기를 감싸고, Combine 게시자를 AsyncSequence 로 연결해 간단한 for await 반복문에서 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Swift Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 2번째 강의입니다.

“기존 콜백/Combine을 async/await로 연결하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 생산자/소비자, 파이프라인, 시간 초과
  2. 기존 콜백/Combine을 async/await로 연결하기
  3. 비동기 코드 테스트(XCTest)
← Swift Academy(으)로 돌아가기