개발을 진행하면서 TabBarController의 특정 탭에서 WriteViewController를
present() 방식으로 모달 띄우는 과정에서 Xcode 경고 메시지가 발생한 경험이 있었다.
이 글에서는 경고 메시지의 원인, 생명주기의 중요성, 그리고 해결 과정을 다뤄보려고한다.
1️⃣ 문제
- TabBarController의 두 번째 탭 선택.
- EmptyViewController가 로드됨.
- EmptyViewController가 로드되자마자 WriteViewController를 present()로 모달 띄움.
- 발생한 Xcode 경고 메시지
Presenting view controller <UINavigationController: 0x104815e00> from detached view controller <LookForRealBurger.EmptyPresentViewController: 0x10360e280> is not supported, and may result in incorrect safe area insets and a corrupt root presentation. Make sure <LookForRealBurger.EmptyPresentViewController: 0x10360e280> is in the view controller hierarchy before presenting from it. Will become a hard exception in a future release.
- 📌 경고 메시지
- 이 경고의 핵심은 ViewController가 View 계층에 완전히 포함되지 않은 상태에서 present()를 호출하고 있다는 것이다
- ⚠️ 발생 가능한 문제
- 잘못된 Safe Area Insets: 레이아웃이 비정상적으로 표시될 수 있음
- 루트 뷰 손상 가능성: 예상치 못한 크래시 발생 가능
- iOS의 향후 버전에서 크래시 가능성 경고
2️⃣ 문제 분석
viewWillAppear(_ animated: Bool)
시점에서 present()를 호출했기 때문이다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let vc = WriteReviewScene.makeView(
tabBar: tabBarController
)
let nav = UINavigationController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
present(nav, animated: true)
}
iOS ViewController 생명주기
- viewWillAppear:
- 뷰가 화면에 나타나기 직전 호출된다.
- 즉, 화면 전환이 일어나기 직전에 호출.
- 아직 뷰 계층에 완전히 추가되지 않은 상태.
- viewIsAppearing:
- 뷰 계층에 추가된 후 호출된다.
NOTE
viewWillAppear는 뷰가 아직 계층에 완전히 포함되지 않은 시점이라서,
이 상태에서 present()를 호출하면 경고가 발생할 수 있다.
3️⃣ 해결을 위한 접근 방식
1. DispatchQueue.main.async 사용
- viewWillAppear에서 present()를 사용하는 대신, 비동기적으로 지연시키는 방식.
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) DispatchQueue.main.async { [weak self] in guard let self else { return } let vc = WriteReviewScene.makeView( tabBar: tabBarController ) let nav = UINavigationController(rootViewController: vc) nav.modalPresentationStyle = .fullScreen present(nav, animated: true) } }
- 장점
- 경고 메시지가 사라짐
- 단점
- 직관적이지 못해 유지보수하기 어려움
- viewWillAppear에서 불필요한 비동기 호출을 사용
2. viewIsAppearing 사용 (권장)
- 뷰 계층에 완전히 추가된 상태인 viewIsAppearing에서 present()를 호출하는 방식.
override func viewIsAppearing(_ animated: Bool) { super.viewIsAppearing(animated) let vc = WriteReviewScene.makeView( tabBar: tabBarController ) let nav = UINavigationController(rootViewController: vc) nav.modalPresentationStyle = .fullScreen present(nav, animated: true) }
- 장점
- 생명주기 원칙 준수: 뷰 계층이 완전히 설정된 후 Present
- 경고 메시지 사라짐
- 안정적인 뷰 전환
4️⃣ 결과 및 성과
- Xcode 경고 제거: viewIsAppearing 사용으로 경고 완전히 제거.
- 안정성 확보: 잘못된 Safe Area Insets 및 크래시 방지.
- 사용자 경험 개선: 안정적인 화면 전환으로 UX 강화.
- 코드 품질 향상: 생명주기를 준수하여 유지보수성 개선.
NOTE
왜 viewIsAppearing가 적합한가?
Apple의 공식 문서에서는, "뷰가 화면에 보여지기 직전의 시점"
"뷰의 frame, bounds, safe area insets, margins 등이 모두 설정된 상태" 로
이미 뷰 계층에 포함된 상태로 컨텐츠를 업데이트 하기에 적합한 상태라고 설명하고 있으며
이는 뷰가 완전히 계층에 추가된 후 화면 전환을 진행하는 것이 안전하고 안정적이라는 것을 의미한다.
5️⃣ 결론
- ViewController 생명주기를 깊이 이해하는 것이 중요하다.
- viewWillAppear는 뷰가 완전히 계층에 추가되기 전 시점이다.
- viewIsAppearing는 뷰가 완전히 계층에 추가된 후 호출되어 모달 전환에 적합하다.
👉 구글링과 경고 메시지에 의존하지 말고, 생명주기와 뷰 계층을 이해하는 것이 중요하다.
'프로젝트 > LookForRealBurger' 카테고리의 다른 글
UIKit 기반 프로젝트에서 Clean Architecture + MVVM-C 설계 (0) | 2025.01.22 |
---|---|
Secure Enclave와 Keychain을 활용한 Refresh Token 보안 관리 (0) | 2025.01.06 |
Unit Test - Mock 객체 메서드 내 분기처리 (0) | 2024.12.30 |
Pull To Refresh - 당겨서 새로고침 UX 개선 (0) | 2024.12.29 |
'LookForRealBurger' 라는 주제로 LSLP 를 진행하고 난 후 (3) | 2024.09.08 |