Continuation
- 동기/콜백 기반 코드를
async/await로 연결해 주는 어댑터
continuation.resume
중단된 async 작업을 재개시키는 트리거 (1회 호출)
-
resume() -> Void 반환
-
resume(returning: value) -> 성공 값 전달
-
resume(throwing: error) -> 에러 전달 (Error 타입)
-
resume(with: result) -> Result<Success, Error> 그대로 전달
콜백 기반 API → async/await (단발성 결과)
// 기존: completion 기반
func fetchUserWithCompletion(completion: @escaping (User) -> Void) {
...
completion(user)
}
// 전환: async (성공만, 에러 미포함)
func fetchUser() async -> User {
await withCheckedContinuation {
(continuation: CheckedContinuation<User, Never>) in
fetchUserWithCompletion { user in
continuation.resume(returning: user)
}
}
}
에러 있는 콜백 → async/await (throws)
// 기존: Result 기반 콜백
func fetchUserWithCompletion(completion: @escaping (Result<User, Error>) -> Void) {
...
if let user {
completion(.success(user))
} else {
completion(.failure(Error.failed))
}
}
// 전환: async throws
func fetchUser() async throws -> User {
try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<User, Error>) in
fetchUserWithCompletion { result in
// switch로 success/throwing 분기
switch result {
case .success(let user):
continuation.resume(returning: user) // 성공 값 전달
case .failure(let error):
continuation.resume(throwing: error) // 에러 전달
}
// (또는) 성공/실패를 그대로 전달
continuation.resume(with: result)
}
}
}
UnsafeContinuation
func fetchUser() async throws -> User {
try await withUnsafeThrowingContinuation {
(continuation: UnsafeContinuation<User, Error>) in
fetchUserWithCompletion { result in
// 체크 없음: 중복/누락 가능
continuation.resume(with: result)
}
}
}
델리게이트 기반 API → async/await (단발성 이벤트)
기존 (델리게이트 방식)
var currentLocation: CLLocation?
func locationManager(
_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]
) {
guard let location = locations.last else { return }
// 즉시 delegate에서 처리
self.currentLocation = location
}
// 다른 곳에서 나중에 접근 (저장된 위치 사용)
if let location = currentLocation {
print("\(location)")
}
async/await + Continuation
var currentContinuation: CheckedContinuation<CLLocation, Error>?
// await로 위치값을 기다릴 수 있는 비동기 함수로 전환
func getCurrentLocation() async throws -> CLLocation {
try await withCheckedThrowingContinuation { continuation in
// (1) continuation 외부 저장
currentContinuation = continuation
locationManager.requestLocation()
}
}
func locationManager(
_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]
) {
guard let location = locations.last else { return }
// (2) 값 반환 시점에 재개
currentContinuation?.resume(returning: location)
// (3) 재개 후 해제
currentContinuation = nil
}
Continuation
async/await로 연결해 주는 어댑터CheckedContinuation (런타임에 오류 체크하는 객체)
withCheckedContinuationwithCheckedThrowingContinuationUnsafeContinuation (런타임에 오류 체크하지 않는 객체, 퍼포먼스 좋음)
withUnsafeContinuationwithUnsafeThrowingContinuationcontinuation.resume
중단된
async작업을 재개시키는 트리거 (1회 호출)resume()-> Void 반환resume(returning: value)-> 성공 값 전달resume(throwing: error)-> 에러 전달 (Error 타입)resume(with: result)->Result<Success, Error>그대로 전달콜백 기반 API →
async/await(단발성 결과)기존 completion을 그대로 감싼 async 함수로 전환
성공만 있는 경우 →
CheckedContinuation<Success?, Never>에러 있는 콜백 →
async/await(throws)Result 에러 콜백을
async throws로 전환성공/실패가 있는 경우
withCheckedThrowingContinuation로 전환resume(throwing:)의 파라미터는 Error 타입이어야 함이미 Result로 받는다면
resume(with: result)로 바로 전달델리게이트 기반 API → async/await (단발성 이벤트)
기존 (델리게이트 방식)
델리게이트 메서드가 불리는 시점에 콜백 내부에서 값이 전달됨
값을 저장해두고 필요할 때 조회
async/await + Continuation
await로 값을 기다릴 수 있는 비동기 함수로 전환Continuation 생성 메서드로 결과값 활용
비동기적으로 생기는 값을
await기다렸다가 받아서 활용델리게이트에서
resume으로 재개 -> 흐름 제어가 동기 코드처럼 작성