← Study Hub

05 · Continuation

resume을 두 번 하면? 안 하면? checked와 unsafe의 갈림길
진행률
0 / 0 완료

← 문항 인덱스

면접 질문
  1. resume을 두 번 호출하면? 한 번도 안 하면? (checked vs unsafe에서 각각)
  2. 콜백이 호출 안 될 수도 있는 API(타임아웃 없는 delegate 등)는 어떻게 감싸나요?

답변 ① — 두 번은 터지고, 영(0)번은 영원히 안 끝난다 🔥 핵심

continuation의 계약은 정확히 한 번 resume입니다. 이 계약을 어겼을 때 checked와 unsafe의 반응이 갈립니다.

두 번 resume하면 — checked는 런타임이 감지해 트랩(크래시)시키고 "resume its continuation more than once" 진단을 냅니다. unsafe는 정의되지 않은 동작(UB)으로, 검사가 없어 진단도 없이 메모리 손상이나 조용한 오작동이 날 수 있습니다.

한 번도 resume하지 않으면 — 여기서 핵심은 공통 결과입니다. 그 task는 영원히 suspend되어 재개되지 않습니다(조용한 무한 대기 + 누수). checked는 continuation이 resume 없이 해제될 때 "leaked its continuation" 경고 로그를 남기지만 콘솔에 한 줄 지나갈 뿐이고, unsafe는 그 경고조차 없습니다.

계약 위반 withCheckedContinuation withUnsafeContinuation
resume 두 번런타임 트랩 + 명확한 진단UB — 진단 없음
resume 안 함무한 대기 + "leaked" 경고 로그무한 대기 · 로그 없음
런타임 비용약간의 검사 오버헤드없음
기본 선택개발 중 기본값검증된 핫패스만
⚠️ 주의

"resume을 안 하면 경고가 뜬다"까지만 답하면 부족합니다. 진짜 문제는 경고가 아니라 그 task가 영영 끝나지 않는다는 것입니다. 사용자 눈에는 "로딩이 끝없이 도는 화면"으로 나타나고, 로그는 아무도 보지 않습니다.

답변 ② — resume을 정확히 1회로 강제하고, 타임아웃을 건다

콜백이 안 올 수도 있는 API를 감쌀 때는 resume이 정확히 1회 일어나도록 세 겹으로 방어합니다.

요점은 "성공 경로에서만 resume하면 안 된다"는 것입니다. 실패·타임아웃·취소 모든 종료 경로에서 정확히 한 번씩 resume되도록 설계해야 합니다.

콜백 API를 async로 감싸기 — '정확히 1회' resume 가드 (Swift)
func fetchImage(_ url: URL) async throws -> UIImage {
    try await withCheckedThrowingContinuation { continuation in
        var didResume = false                  // ← 정확히 1회 보장

        legacyFetch(url) { result in
            guard !didResume else { return }    // 두 번째 콜백은 무시(중복 resume 방지)
            didResume = true
            continuation.resume(with: result)
        }

        // ⚠️ 이 클로저가 resume 없이 끝나면 → 호출자는 영원히 깨어나지 못한다
        // ⚠️ resume을 두 번 하면 → checked = 크래시(진단) / unsafe = UB(조용히 망가짐)
        // → 실전에서는 여기에 타임아웃 경합과 취소 핸들러를 함께 건다
    }
}

쉽게 이해하기

continuation은 "다 끝나면 이 호출벨 눌러줘"라고 맡겨 둔 벨이에요. 나는 벨이 울릴 때까지 그 자리에서 기다립니다.

(질문 ①) 벨을 두 번 누르면 시스템이 놀라서 뻗어요. checked는 "야, 벨 두 번 눌렀어!" 하고 대놓고 알려주면서 멈추고, unsafe는 아무 말 없이 어딘가 조용히 망가집니다. 벨을 한 번도 안 누르면 더 무서워요. 기다리던 나는 영원히 그 자리에 서 있습니다. checked는 그나마 "너 벨 안 눌렀네?" 하고 작게 중얼거리지만, unsafe는 그마저도 없어요. 둘 중에는 대놓고 알려주는 쪽이 훨씬 나으니, 개발할 때는 checked를 씁니다.

(질문 ②) 그래서 연락을 잘 까먹는 상대한테 일을 맡길 때는 이렇게 합니다. 먼저 "벨은 딱 한 번만" 이라고 잠금장치를 걸고, 알람 시계를 같이 맞춰 둡니다. 시간이 다 됐는데도 연락이 없으면 알람이 대신 벨을 눌러줘요. 그러면 최소한 "실패했어"라고 끝낼 수는 있으니, 영원히 기다리는 일은 없어집니다.

🔑 한 문장

벨은 정확히 한 번. 두 번이면 터지고, 영(0)번이면 영원히 안 끝난다.