iOS における viewWillDisappear — メソッドの本質と正しい使い方

著者: IT Sectr 公開日: 2026-03-05 読了時間: 8 分

viewWillDisappear は UIViewController のメソッドで、UIKit が画面がユーザーのディスプレイから消え始める直前に呼び出します。Apple Developer Documentationによると、このメソッドは animated パラメーターを受け取り、push、pop、present、 dismiss およびタブ切り替え時に発火します。 viewWillDisappear は状態を保存し、リソースを正しくクリアなるための主な場所です。

ポイント

  • viewWillDisappear は各画面消失の前に呼ばれる
  • 一時データやドラフトの状態保存に使用される
  • NotificationCenter および KVO からのサブスクライブ解除はこのメソッドでの必須タスク
  • メソッドはキャンセルされたジェスチャーでも呼ばれる可能性がある — viewDidDisappear でデータを複製する
  • super.viewWillDisappear は正しいナビゲーションのために必須

viewWillDisappear とは

viewWillDisappear は UIViewController のメソッドで、コントローラの View が画面から消え始める直前に UIKit が呼び出します。この瞬間、画面はまだユーザーに見えていますが、トランジションはすでに開始されています: NavigationController が push/pop アニメーションを開始し、モーダル ビューが閉じ始め、または TabBar が別のタブに切り替え始めます。開発者は、画面がまだアクセス可能であることが必要であるが、隠す準備をする操作を実行するために、このメソッドをオーバライドします。

viewDidDisappear が画面が隠れた後に発火するのとは対的に、viewWillDisappear はユーザーがまだインターフェースを見ているうちに、データを保存し、リソースを解放する最後の機会を提供します。これは UX にとって非常に重要です — ドラフトの保存やタイマーの停止は、ユーザーが別の画面に切り替える前に実行される必要があります。

メソッドは animated パラメーターを受け取り、消失がアニメーションかどうかを示します。true は UIKit がアニメーション付きのトランジションを実行していることを意味し、false は画面が即時に消えることを意味します。例えば、アニメーションなしの dismiss やプログラムによるヒエラルキからの削除などです。

viewWillDisappear が呼ばれるタイミング

viewWillDisappear は、現在の画面がアクティブでなくなるあらゆるシナリオで呼ばれます。iOS 開発に特有の主なケースを確認しましょう。

新しい画面を push する際

UINavigationController が新しいコントローラを push すると、トランジション アニメーションの開始時に現在のコントローラで viewWillDisappear が呼ばれます。この瞬間、現在の画面は上にスライドしてくる新しいコントローラの下でまだ見えています。これが標準的なシナリオで、viewWillDisappear は animated = true で発火します。

現在の画面を pop する際

ユーザーが戻るボタンをタップするか、インタラクティブ・スワイプで戻ると、現在のコントローラで viewWillDisappear が呼ばれます。インタラクティブ・ジェスチャーの場合、ユーザーが意を変えて画面を元の位置に戻すと、この呼び出しはキャンセルされることがあります。状態保存を設計する際には、この重要な特徴を考慮する必要があります。

swift
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    saveDraftData()
    NotificationCenter.default.removeObserver(self)
}

コントローラを dismiss する際

モーダル ビューを閉じる際、 dismiss アニメーションの開始時に、閉じられるコントローラで viewWillDisappear が呼ばれます。この時点でデリゲートまたはクロージャを通して結果を戻すことができます。なぜなら、モーダルを提示したコントローラはまだ制御を取り戻していないからです。

TabBar のタブ切り替え時

UITabBarController は、ユーザーが別のタブをタップした直後に、离れるタブのコントローラで viewWillDisappear を呼びます。現在のタブにアクティブなプロセスがある場合 — メディア再生、ファイルダウンロード、タイマー — ここで一時停止または停止する必要があります。

viewWillDisappear での実務的なタスク

viewWillDisappear は、リソースおよび状態管理に関する特定のタスクを解決します。コード例を使って主なシナリオを確認しましょう。

ユーザーデータの保存

viewWillDisappear の最も重要なタスクは、現在の画面でユーザーが入力または変更したデータを保存することです。メッセージの一時保存、編集されたフォームのフィールド、選択された設定 — これらはすべて、画面が消える前に保存する必要があります。持続化には Core Data、UserDefaults またはファイルストレージを使用してください。

swift
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    guard hasUnsavedChanges else { return }
    draftStorage.save(currentDraft)
}

通知からのサブスクライブ解除

viewWillAppear または viewDidLoad でサブスクライブした NotificationCenter、KVO および Combine パブリッシャーは、viewWillDisappear でキャンセルする必要があります。そうしないと、通知が隠れた画面に届き、ユーザーが見ていない UI 更新が起こったり、さらに悪い場合は、すでに解放されたオブジェクトへのアクセスによるクラッシュが発生する可能性があります。

アニメーションとタイマーの停止

viewDidAppear で開始した UIView アニメーションや、Timer または DispatchSource を通じて動作するタイマーは、viewWillDisappear で停止する必要があります。隠れた画面でアニメーションが続くと、ユーザーに何の利益もなくGPU とバッテリーを消費します。タイマーに invalidate を、レイヤーに removeAllAnimations を呼び出して明示的に停止してください。

swift
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    countdownTimer?.invalidate()
    countdownTimer = nil
    loadingIndicator.layer.removeAllAnimations()
}

データを戻す

コントローラが結果を得るために開かれた場合 — アイテムの選択、テキストの入力、アクションの確認 — viewWillDisappear は、元のコントローラがまだスタックに存在し、データを受け取ることができる最後の瞬間です。deinit が呼ばれる前にデリゲートまたはクロージャを呼び出してください。

状態保存ストラテジー

信頼性のある状態保存は、iOS 開発における最も難しいタスクの一つです。viewWillDisappear は重要ですが、ストラテジーの唯一の要素ではありません。総合的なアプローチを見てみましょう。

レベル 1 — viewWillDisappear での保存。戻ってきた直後にすぐに利用可能であるべき、軽いデータの高速保存。UI 状態に適しています: スクロール位置、選択されたセグメント、入力フィールドのテキスト。問題: キャンセルされたインタラクティブ・ pop ジェスチャーでは、ユーザーが画面にとどまっていても保存が行われます — データが不要に上書きされます。

レベル 2 — viewDidDisappear での保存。第 1 レベルの保存を複製しますが、画面が確実に隠れた後にのみ発火します。これはキャンセルされたジェスチャーに対する保護です。ただし、すでに viewWillDisappear で通知からサブスクライブ解除している場合、viewDidDisappear はいくつかのデータにアクセスできない可能性があります。

レベル 3 — アプリケーション通知による保存。UIApplication.willResignActiveNotification および UIApplication.didEnterBackgroundNotification は、アプリのバックグラウンドをキャッチします。ユーザーがアプリを最小化した場合、viewWillDisappear が呼ばれていない可能性がありますが、これらの通知による保存は、セッション終了時のデータ整合性を保証します。

レベルメソッド/通知信頼性使用
1viewWillDisappear高いUI 状態、ドラフト
2viewDidDisappear非常に高い重要データ
3willResignActive最高アプリバックグラウンド時

推奨: 重要なユーザーデータには、3 つのレベルすべてを組み合わせて使用してください。非重要な状態には、第 1 レベルで十分です。同じデータを繰り返し保存しないことが重要です — dirty フラグを使用して、最終保存以降にデータが変更されたかどうかを示します。

CRUD 画面のストラテジーには特別な注意が必要です。こうした画面では、viewWillDisappear で毎キーストロークを保存することは推奨されません — 過剰です。Timer を通じて遅延 (debounce) を伴う自動保存を使用し、viewWillDisappear は未保存の変更がある場合の最終的な強制保存にのみ使用します。このアプローチは、パフォーマンスとデータ整合性のバランスを取ります。

Core Dataを使用するアプリでは、managed object context に実際の変更がある場合のみ、viewWillDisappear で saveContext を呼ぶことが追加の対策です。保存前に context.hasChanges をチェックすることで、persistent store への不要な書き込みを防ぎ、デバイスのバッテリー寿命を延ばすことができます。このチェックを applicationDidEnterBackground でのグローバル保存と組み合わせてください。

viewWillDisappear での一般的な誤り

不正な使用 viewWillDisappear は、データの失い、メモリーリーク、不安定なアプリ行動を引き起こす可能性があります。頻繁な iOS 開発者の誤りを確認しましょう。

誤りその 1 — viewWillDisappear でのみデータを保存する。上述のように、インタラクティブ・ pop ジェスチャーでは、画面が消えなくてもメソッドが呼ばれます。保存に副作用がある場合 — サーバーへのデータ送信、状態変更 — これにより誤った発火が起こる可能性があります。isBeingDismissed または isMovingFromParent のチェックを追加してください。

誤りその 2 — NotificationCenter からのサブスクライブ解除を忘れる。これは iOS で最もよくあるメモリーリークの一つです。viewWillAppear で UIResponder.keyboardWillShowNotification にサブスクライブしたが、viewWillDisappear でサブスクライブ解除しなかった場合、クロージャは呼ばれ続けます。コントローラの deinit 時に、クロージャが解放済みのオブジェクトを参照するため、アプリのクラッシュが確実に発生します。

誤りその 3 — \u91cdい同期処理の実行。viewWillDisappear で大量のデータ保存、Core Data への書き込み、ファイルシステムへの書き込みは、メインスレッドをブロックします。処理がトランジションアニメーションよりも長くかかる場合、UIKit はスレッドを一時停止し、インターフェースがフリーズします。重い保存はバックグラウンドキューに移してください。

誤りその 4 — super の呼び出しを忘れる。super.viewWillDisappear を呼ばないと、このメソッドを内部状態に使用する UINavigationController や UITabBarController が正常に動作しなくなる可能性があります。Apple のドキュメントに従い、常に super を最初または最後に呼び出してください。

この問題は、アクティブなマルチタスクおよびアプリ切り替えがある iOS で悪化します。誤りその 5 — viewWillDisappear での保存後に DispatchQueue.main.async を使用する。super.viewWillDisappear を呼んだ後にメインキューにブロックを非同期的にディスパッチする場合、ブロック実行時にコントローラがまだ存在するかどうか保証はありません。解放済みのメモリへのアクセスやアプリクラッシュを防ぐために、クロージャ内では常に弱参照 [weak self] を使用してください。

よくある質問

viewWillDisappear と viewDidDisappear の違いは何ですか?

viewWillDisappear は消失の開始時に呼ばれ、画面がまだ見えています。viewDidDisappear は画面が完全に隠れ、アニメーションが終了した後に呼ばれます。

キャンセルされた pop ジェスチャーにどう対処すればいいですか?

保存を確認するにはviewDidDisappearを使用するか、viewWillDisappear 内で isMovingFromParent および isBeingDismissed プロパティをチェックして、画面が実際に消えるかどうかを判断します。

NotificationCenter から手動でサブスクライブ解除する必要はありますか?

はい、必ず self を使ったブロックまたはセレクタを使用する場合は必要です。ARC は NotificationCenter のサブスクリプションを管理しません。iOS 9+ でブロックを使用する場合は、弱参照を使用し、viewWillDisappear でサブスクライブ解除してください。

viewWillDisappear を通じて force quit 時にデータを保存するにはどうすればいいですか?

できません — force quit はライフサイクルメソッドを呼び出しません。アプリ終了時の確実な保存には、UIApplication.willTerminateNotification を使用するか、データが変更されるたびにリアルタイムで保存してください。

コントローラが消えていないのに viewWillDisappear が呼ばれることはありますか?

はい、インタラクティブ・ pop ジェスチャーでは、ジェスチャーが開始した直後に UIKit が viewWillDisappear を呼び出します。ユーザーがジェスチャーをキャンセルすると、画面は見えたままですが、メソッドはすでに実行されています。常に isMovingFromParent をチェックしてください。

まとめ

  • viewWillDisappear は各画面消失の前に呼ばれる — push、pop、present、dismiss 時
  • 主な目的は状態保存、通知からのサブスクライブ解除、アニメーションの停止
  • インタラクティブ・ジェスチャーでは、画面が実際に隠れなくてもメソッドが呼ばれることがある
  • 重要なユーザーデータには 3 レベルの保存ストラテジーを使用する
  • viewWillDisappear での NotificationCenter からのサブスクライブ解除はメモリーリークを防ぐ
  • 重い同期処理はメインスレッドをブロックする — バックグラウンドキューに移す
  • 正しいナビゲーションを維持するために、常に super.viewWillDisappear を呼ぶ

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください