viewDidDisappear는 iOS 기기 화면에서 뷰가 완전히 사라진 직후 호출되는 UIViewController의 생명 주기 메소드입니다. 개발자는 이를 사용하여 애니메이션을 멈추고, RAM을 해제하고, 알림을 구독 해지하며, 현재 상태를 저장합니다. Apple Developer Documentation(2025)에 따르면, 이 메소드의 올바른 구현은 활성적인 네비게이션이 있는 애플리케이션에서 메모리 누수를 최대 40%까지 방지합니다. 이것이 없으면 백그라운드 프로세스가 계속 실행되어 배터리와 CPU 자원을 소비할 수 있습니다. viewDidDisappear의 올바른 사용은 iOS 개발자의 핵심 스킬 중 하나로, 애플리케이션의 성능과 안정성에 직접적으로 영향을 미칩니다.
주요 포인트
viewDidDisappear는 시스템이 화면의 창 계층구조에서 뷰가 완전히 제거된 후에 호출하는 UIViewController 슈퍼클래스의 후크 메소드입니다. 이는 UIKit에서 표준 뷰 생명 주기의 일부로, 개발자에게 마무리 작업을 수행할 수 있는 시점을 제공합니다.
이 메소드는 UIViewController 프로토콜에 선언되며 모든 하위 클래스에서 재정의할 수 있습니다. 메소드 시그니처는: override func viewDidDisappear(_ animated: Bool)입니다. animated 매개변수는 전환에 애니메이션이 포함되었는지 여부를 나타냅니다. 이를 통해 프로그래밍 전환과 애니메이션 전환을 구별하여 더 정확한 동작 제어가 가능합니다.
애니메이션이 시작되기 전에 호출되는 viewWillDisappear와 달리, viewDidDisappear는 뷰가 더 이상 사용자에게 보이지 않는 것을 보장합니다. 이것은 인터페이스가 완전히 숨격지된 후에만 실행되어야 하는 작업에 중요합니다 — 예를 들어, 전체 화면 오버레이 요소를 숨기거나 비디오 녹화를 종료하는 경우들이 있습니다.
이 메소드는 기본 클래스 UIViewController에 정의되며 다음과 같은 시그니처를 가집니다:
import UIKit
class MyViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// 자원 해제 및 구독 해지
}
}
구현의 첫 라인에서 super.viewDidDisappear(animated)를 호출하는 것은 UIKit의 요구 사항입니다. 이것이 없으면 슈퍼클래스는 뷰 표시에 관련된 내부 프로세스를 제대로 완료할 수 없습니다. 이 규칙을 무시하면 예측할 수 없는 네비게이션 동작과 잠재적인 충돌이 발생할 수 있습니다.
완전한 UIViewController 생명 주기는 여섟 개의 핵심 메소드로 구성되며, 각각이 뷰 존재의 특정 단계를 담당합니다. viewDidDisappear는 viewWillDisappear를 따라 사라지는 순서를 완성합니다. 초기화와 자원 해제를 올바르게 분배하려면 모든 메소드의 호출 순서를 이해하는 것이 중요합니다.
뷰가 나타날 때 순서: viewDidLoad → viewWillAppear → viewDidAppear. 숨길 때: viewWillDisappear → viewDidDisappear. 최종 단계는 deinit로, UIViewController 객체가 파괴될 때 호출됩니다. 이 여섯 개의 메소드는 예측 가능한 상태 관리를 보장하는 완전한 사이클을 형성합니다.
| 메소드 | 호출 시점 | 일반적인 사용 |
|---|---|---|
| viewDidLoad | 메모리에 뷰가 로드된 후 | 초기 UI 설정, 데이터 구독 |
| viewWillAppear | 화면에 뷰가 나타나기 전 | 표시 전 데이터 업데이트 |
| viewDidAppear | 화면에 뷰가 나타난 후 | 애니메이션 시작, 관찰 시작 |
| viewWillDisappear | 뷰가 사라지기 전 | 입력 데이터 저장, 작업 취소 |
| viewDidDisappear | 뷰가 사라진 후 | 자원 해제, 알림 구독 해지 |
| deinit | 객체가 파괴될 때 | 최종 정리, 강한 참조 해제 |
이 메소드들은 각각 해당 전환릹 한 번씩 호출됩니다. 예외는 viewDidLoad로, 자원 필요에 따라 ViewController가 메모리에서 언로드된 후 복구되는 경우 다시 호출될 수 있습니다. 이런 경우 viewDidDisappear는 반복된 viewDidLoad 전에 호출됩니다.
메소드 시그니처의 animated 매개변수는 전환이 애니메이션되었는지 여부를 나타냅니다. 이것은 애니메이션 없는 프로그래밍 전환(예: rootViewController 설정)과 사용자가 시작한 애니메이션 전환을 구분하는 데 유용합니다. 값이 false인 경우, 컨트롤러가 시스템에 의해 강제로 숨겨졌을 수 있습니다 — 이런 경우 일부 시간 의존 작업이 무의미하지 않을 수 있습니다.
시스템은 viewDidDisappear를 또 두 가지 상황에서 호출합니다: ViewController가 네비게이션 스택에서 제거될 때와 다른 컨트롤러에 의해 가려질 때입니다. 두 경우 모두에서, 메소드는 뷰가 더 이상 사용자에게 보이지 않음을 알리고, 개발자는 백그라운드에서 필요 없는 자원을 해제해야 합니다. 이러한 상황을 이해하면 애플리케이션 상태에 대한 잘못된 가정을 방지할 수 있습니다.
첫 번째 상황 — UINavigationController에서 pop. 사용자가 뒤로 가기 버튼을 누르면 popViewController:animated가 호출됩니다. 현재 컨트롤러는 viewDidDisappear를 받아오고, 그 후 강한 참조가 더 이상 없으면 deinit이 호출됩니다. 둘 째 상황 — present/dismiss. 새로운 컨트롤러가 모달로 표시될 때 presentingViewController는 viewDidDisappear를 받습니다. dismiss 시, 이 메소드는 모달로 표시된 컨트롤러에서 호출됩니다.
세 번째, 몇 되지 않은 상황 — child ViewController 추가. 컨테이너 컨트롤러(예: UIPageViewController 또는 UITabBarController)에 새 하위 컨트롤러가 추가되면, 활성화된 하위 컨트롤러는 viewDidDisappear를 받습니다. 이것은 탭 또는 페이지 캐러셜이 있는 애플리케이션에 중요합니다 — 탭 전환마다 비활성 화면의 작업을 정확히 일시 중단해야 합니다.
중요한 예외가 있습니다: UIViewController가 모달 창에 표시되고 사용자가 아래로 스와이프하여 인터랙티브로 닫는 경우, 제스처가 완료되지 않으면 시스템이 viewDidDisappear를 호출하지 않을 수 있습니다. 이 동작은 iOS 13에서 인터랙티브 디스미스와 함께 나타났습니다. 개발자는 UIAdaptivePresentationControllerDelegate 및 didDismiss 메소드를 통해 이벤트 수신을 보장해야 합니다.
또 다른 특징 — 메모리 경고. 메모리가 부족할 때, 시스템은 화면에 보이지 않는 컨트롤러의 뷰를 언로드할 수 있습니다. 이경우 viewDidDisappear는 보통 언로드 전에 호출되지만, 개발자는 안전 장치로 didReceiveMemoryWarning에서 중요한 정리 작업을 복제해야 합니다. 이 접법은 극단적인 상황에서 데이터 손실을 방지합니다.
viewDidDisappear는 세 가지 주요 작업 카테고리에 사용됩니다: 활동 중지, 자원 해제, 상태 저장. 각 카테고리에는 iOS 개발자 커뮤니티에서 개발한 최고의 실무가 있습니다. 구현 예제와 함께 가장 일반적인 상황을 살펴보겠습니다.
일반적인 실수는 viewDidLoad에서 알림에 구독하고 구독을 해지하지 않는 것입니다. 이로 인해 해제된 객체에서 핸들러가 호출되어 충돌이 발생합니다. 올바른 접근 방식은 viewWillAppear에서 구독하고 viewDidDisappear에서 구독을 해지하는 것으로, 컨트롤러가 화면에 표시되는 동안만 구독이 활성화되도록 합니다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleKeyboardShow),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
이 패턴은 알림 핸들러가 컨트롤러가 화면에 보일 때만 활성화되도록 보장합니다. 다른 화면으로 이동할 때 모든 구독이 자동으로 제거되고, 돌아올 때 복구됩니다. 이를 통해 애플리케이션의 신뢰성이 향상되고 알림관련 버그 문제가 해결됩니다.
실제 프로젝트에서 viewDidDisappear을 사용하는 두 가지 실용적인 예를 살펴보겠습니다. 첫 번째 예는 화면이 숨겨질 때 타이머를 멈추는 것이고, 둘 째는 키보드 관찰을 올바르게 종료하는 것입니다. 두 예 모두 컨트롤러가 비활성일 때 자원을 해제하는 원칙을 따릅니다.
화면에서 UI를 업데이트하기 위해 Timer가 실행되고 있는 경우(예: 카운트다운 또는 캐러셜), 컨트롤러가 숨겨질 때 타이머를 멈추어야 합니다. 백그라운드에서 타이머를 계속 실행하면 CPU 자원을 소비할 뿔만 아니라, 보이지 않는 UI를 업데이트하려는 시도에서 예외가 발생할 수 있습니다.
class CountdownViewController: UIViewController {
private var countdownTimer: Timer?
private var remainingSeconds: Int = 60
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startTimer()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
invalidateTimer()
}
private func invalidateTimer() {
countdownTimer()?.invalidate()
countdownTimer = nil
}
}
많은 애플리케이션에서 AVPlayer가 내장 플레이어에서 비디오를 재생합니다. 사용자가 다른 화면으로 텭하면 비디오가 자동으로 일시 중단되어야 합니다. viewDidDisappear에서 이를 구현하면 화면이 완전히 숨겨진 후에 일시 중단되도록 보장됩니다 — 이를 통해 전환 중 검은 화면 깜빠임을 방지할 수 있습니다.
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if player().timeControlStatus == .playing {
player().pause()
playerLayer().removeFromSuperlayer()
}
player = nil
}
일시 중단 후 player 변수를 달이하면 비디오 버퍼가 차지하던 메모리가 추가로 해제됩니다. 이 접근 방식은 버퍼가 수십 메가바이트를 차지할 수 있는 긴 비디오를 다루는 애플리케이션에 특히 중요합니다. 일시 중단과 참조 달이를 결합하면 백그라운드에서 애플리케이션의 걸음이를 최소화할 수 있습니다.
viewDidDisappear는 종종 viewWillDisappear 및 deinit과 혼동되지만, 각 메소드에는 고유한 역할이 있습니다. 그들 사이의 경계를 이해하는 것이 안정적인 iOS 애플리케이션 아키텍처의 열쇠입니다. 올바르지 않게 사용하면 자원이 중복으로 해제되거나, 반대로 자원 누수가 발생할 수 있습니다.
viewDidDisappear와 viewWillDisappear의 주요 차이점은 호출 시감입니다. viewWillDisappear는 뷰가 여전히 보이지만 사라지려고 하는 때 호출됩니다. 이것은 보이는 데이터(입력 필드의 텍스트)를 저장하는 데 적합합니다. viewDidDisappear는 애니메이션이 완료된 후, 뷰가 확실히 보이지 않을 때 호출됩니다 — 시각적 상태와 무관한 자원을 해제하는 데 이상적입니다.
deinit은 viewDidDisappear와 달리 UIViewController 객체가 메모리에서 파괴될 때만 호출됩니다. 컨트롤러가 단순히 숨겨진 경우(예: 모달 창에 가려진 경우) deinit은 호출되지 않습니다. 이런 상황에서 viewDidDisappear가 마무리 작업을 수행하는 유일한 시점입니다. 완전한 자원 정리는 deinit에서 다루어야 하지만, viewDidDisappear는 다음 나타날 때까지 임시 해제를 처리합니다.
SwiftUI로 개발할 때 viewDidDisappear 메소드는 사용되지 않습니다 — 대신 .onDisappear 수정자가 사용되며 비슷한 방식으로 작동합니다. 그러나 SwiftUI는 직접적인 생명 주기 제어가 부재하며, 개발자는 Combine과 State 객체에 의존하여 자원을 관리합니다. UIKit 애플리케이션에서 viewDidDisappear는 화면 사라짐을 관리하는 주요 도구로 남아 있습니다.
경험 있는 iOS 개발자도 viewDidDisappear을 사용할 때 실수를 합니다. 가장 일반적인 다섟 가지 문제와 예방 방법을 살펴보겠습니다. 이러한 안티 패턴을 알면 컨트롤러 생명 주기와 관련된 잡기 어려운 버그를 피할 수 있습니다.
스레드 안전성에 특히 주의해야 합니다. viewDidDisappear가 메인 스레드에서 호출되는 경우(UIKit에 의해 보장됨), 자원 정리에 비동기 작업이 포함된 경우 공유 데이터에 대한 접근을 동기화해야 합니다. 비동기 작업 완료 후 UI를 업데이트하기 위해 viewDidDisappear 내에서 DispatchQueue.main.async를 사용하는 것은 일반적이지만 올바른 접근 방식입니다.
또 다른 중요한 안티 패턴 — viewDidDisappear 내에서 데리게이트 메소드 호출하며 이것이 새 전환이나 모달 표시를 시작할 수 있습니다. 이로 인해 첫 번째 호출이 완료되기 전에 viewDidDisappear가 다시 호출되는 순환이 발생할 수 있습니다. Apple은 생명 주기 메소드 내에서 모달 표시를 피하고 별도의 이벤트 핸들러로 옮길 것을 권장합니다.
자주 묻는 질문
viewWillDisappear는 숨김 애니메이션이 시작되기 전, 뷰가 여전히 보일 때 호출됩니다. viewDidDisappear는 뷰가 완전히 사라진 후에 호출됩니다. 데이터 저장에는 viewWillDisappear를, 자원 해제에는 viewDidDisappear를 사용하십시오.
네, super.viewDidDisappear(animated)를 호출하는 것은 필챨적입니다. UIKit은 이 메소드를 내부 알림과 전환 상태 완료에 사용합니다. super 호출이 없으면 UINavigationController와 UITabBarController가 오류를 일으킬 수 있습니다.
네, iOS 13+에서 인터랙티브 디스미스(아래로 스와이프)를 사용할 때 제스처가 완료되지 않으면 메소드가 호출되지 않을 수 있습니다. 이벤트 수신을 보장하려면 UIAdaptivePresentationControllerDelegate 위임 및 presentationControllerDidDismiss 메소드를 사용하십시오.
deinit은 객체가 파괴될 때만 호출되지만, viewDidDisappear는 숨길 때마다 호출됩니다. 전환마다 자원을 해제하는 경우(예: 알림 구독 해지) viewDidDisappear를 사용하고, 컨트롤러가 제거될 때 최종 정리에는 deinit을 사용하십시오.
SwiftUI에서는 viewDidDisappear 대신 .onDisappear { } 수정자가 사용됩니다. 뷰가 계층구조에서 사라질 때 호출됩니다. UIKit과 달리 SwiftUI는 모든 애니메이션 상황에서 onDisappear가 호출된다는 것을 보장하지 않습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.