UNUserNotificationCenter `requestAuthorization`에서 발생하는 희귀한 버그 현상 분석
예전에 작성된 코드에서 앱이 멈추는 상황이 발생해서 사례 분석
상세한 분석 링크
https://github.com/lgvv/unusernotificationcenter-requestauthorization-blocking-simulation
GitHub - lgvv/unusernotificationcenter-requestauthorization-blocking-simulation: Investigating Rare Bugs in UNUserNotificationCe
Investigating Rare Bugs in UNUserNotificationCenter’s RequestAuthorization on iOS - lgvv/unusernotificationcenter-requestauthorization-blocking-simulation
github.com
정상 동작 흐름
thread : main
- 사용자가 버튼을 클릭하여 권한 요청 로직을 트리거
- Apple iOS 시스템 Public API 호출
- 메인 스레드에서 DispatchSemaphore.wait()가 호출되어 동기 대기
- 시스템 API의 completion handler에서 콜백
- 콜백 내부에서 semaphore.signal()을 호출하여 대기 해제
- 이후 코드 실행이 재개되어 앱 진입 로직이 정상적으로 수행
문제 발생 흐름
thread : main
- 사용자가 버튼을 클릭하여 권한 요청 로직을 트리거. ✅
- Apple iOS 시스템 Public API 호출 ✅
- 메인 스레드에서 DispatchSemaphore.wait()가 호출되어 동기 대기 ✅
- 시스템 API 콜백(completion handler)이 호출되지 않음. ❌ 응답 없는 지점.
- semaphore.signal()이 실행되지 않아 대기 상태가 해제되지 않음. ❌
- 이후 코드 실행이 재개되지 않고, 앱이 해당 지점에서 멈춤 ❌
오류 상황 발생시 실험
클로저가 백그라운드에서 실행될 수 있다고 공식문서에 적혀 있음.
> 내부적으로 스레드 전환 가능성 있음.
클로저 기반의 코드를 확인
> 콜백이 오지 않음
private func calling() {
    // thread: main
    let semaphore = DispatchSemaphore(value: 0)
    
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.criticalAlert]) { _, _ in
        semaphore.signal() // ❗️ Missing callback -> MainThread Block
    }
    semaphore.wait()
    
    // ...
}
애플 공식 문서를 참고하여 Swift Concurrency 코드를 확인
> await 지점을 즉시 지나감.
private func calling2() {
    Task { @MainActor in
        // thread: main
        let center = UNUserNotificationCenter.current()
        do {
            if try await center.requestAuthorization() == true {
                // Authorized
            } else {
                // Not authorized
            }
        } catch {
            // Handle error
        }
    }
    // ❗️ The await does not suspend; execution continues immediately
}
해결
해당 현상이 발생할 경우 재부팅 전까지 requsetAuthorization에서 callback이 영구적으로 오지 않음.
재부팅 후에는 정상화
조치
애플 기술 문의
> 기술 문의는 영어로 해야하고, 샘플 프로젝트와 자세한 설명 등이 필요
애플 기술 문의 답변
> Xcode 26.1 베타 설치해보고 해당 버전에서도 문제가 발생하면 알려달라는 회신
유의할 점
Xcode 26에서 Default isolation MainActor로 변경할 때 시스템 API의 응답이 없을 수도 있어서 메인스레드를 잠그는 코드가 없는지 체크
'project > 개발 업무' 카테고리의 다른 글
| l-value, r-value (0) | 2025.10.23 | 
|---|---|
| Actor에서 Class + OSAllocatedUnfairLock (2) | 2025.08.06 | 
| Swift Concurrency Task weak self 실험 정리 (0) | 2025.07.29 | 
| Tuist CocoaPod 연동 (0) | 2025.07.05 | 
| (Concurrency, Combine) 전역 이벤트 관리 (1) | 2025.05.31 |