.onAppear: 動作原理、ライフサイクル、SwiftUIでの例

著者: IT Sectr 公開日: 2026-06-26 読了時間: 10 分

.onAppearは、Viewがインターフェース階層に追加されたときにクロージャを実行するSwiftUIモディファイアです。呼び出しは画面上のインスタンスの出現ごとに1回発生し、データのロード、アニメーションの開始、分析イベントの送信のための主要ポイントとして機能します。Apple Developer Documentation(2026年)によると、onAppearは最初のレンダリング前に実行を保証しますが、Viewがメモリに残っている場合、繰り返し表示されるたびに呼び出されることは保証しません。SwiftUIの詳細については、SwiftUIの記事をお読みください。

重要なポイント

  • .onAppear — 画面上にViewが表示されたときにコードを実行するSwiftUIモディファイアです。
  • 単回実行 — onAppearはViewがメモリに残っている場合、Viewのライフサイクルごとに1回呼び出されます。
  • データロード — onAppearの主な使用例:APIからのフェッチ、Core DataまたはUserDefaultsからの読み取り。
  • アニメーション — onAppearはエントリアニメーション(opacity、scale、offset)を遅延付きで開始します。
  • 分析 — screen view、impression、page openイベントはonAppearを介して送信されます。

.onAppearとは?

.onAppearは、Voidクロージャを受け取り、Viewが画面に表示されたときに実行するSwiftUIのViewモディファイアです。このモディファイアは、.onDisappearや.taskとともにSwiftUIコンポーネントのライフサイクルシステムの一部です。Appleは、UIKitのviewDidLoadの代替として、SwiftUIのiOS 13およびwatchOS 6のリリースとともにonAppearを導入しました。

構文的に、.onAppearは任意のViewを変更し、アクションが添付された同じViewを返します。SwiftUIコンポーザーは、Viewが階層に追加されてレンダリング段階を通過したときに、渡されたクロージャを1回呼び出します。Viewが削除されて再び追加された場合(たとえば、リストのスクロール時)、onAppearは再び呼び出されます — この動作はしばしば予期しないバグの原因になります。

onAppearの構文

モディファイアの基本的な構文は最小限です:パラメータなしのonAppear。SwiftUIには優先度やアニメーションを渡す方法はありません — クロージャはレンダリング直後にメインスレッドで同期的に実行されます。

swift
struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI!")
            .onAppear {
                print("View appeared on screen")
            }
    }
}

制限:onAppearはasync/awaitを直接サポートしていません。クロージャ内での非同期操作には、Task {}またはTask.detachedを介して呼び出される別のasync/await関数が必要です。これにより、onAppearは.taskモディファイアと比較してネットワークリクエストにあまり便利ではありません。

.onAppearがViewライフサイクルでどのように機能するか

.onAppearは、layout+render段階でSwiftUIレンダリングパイプラインに組み込まれています。SwiftUIがViewの本文を計算し、階層の変更を検出すると、新しく追加されたすべてのViewに対してonAppearコールバックを起動します。呼び出し順序はネストに従います:最初に親のonAppear、次に子要素です。

SwiftUIの重要な特徴は、onAppearが物理的な画面表示に結びついていないことです。モディファイアは、Viewがユーザーに表示されるかどうかに関係なく(たとえば、ScrollViewで画面外にある場合でも)、階層に追加されると呼び出されます。これにより、viewWillAppearが実際の表示時にのみ起動するUIKitとは異なります。

onAppearの呼び出し順序

呼び出し順序は親優先ルールに従います:VStackまたはNavigationViewが最初にonAppearを受け取り、次に各子要素が順番に受け取ります。これは共有リソースの初期化にとって重要です:子要素が親によってロードされたデータに依存する場合、Optionalを介して利用可能性を確認する必要があります。

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView()
            ChildView()
        }
        .onAppear {
            print("Parent onAppear — first")
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("Child")
            .onAppear {
                print("Child onAppear")
            }
    }
}

コンソール出力は次のようになります:最初にParent onAppear、次に順番にChild onAppearが2回。この動作はAppleによって保証されており、すべてのSwiftUIバージョン(iOS 13–18)で安定しています。

.onAppearが呼び出されるタイミング

.onAppearには、コンテナとナビゲーションに依存するいくつかの呼び出しシナリオがあります。NavigationStackでは、onAppearは新しいコントローラのプッシュごと、およびポップ時にルートコントローラに対して起動されます。TabViewでは、タブの切り替えにより、表示されているタブにonAppearが、非表示のタブにonDisappearが呼び出されます。

ListおよびScrollViewでは、可視領域に入ったセルまたはプリレンダリングバッファ内のセルに対してonAppearが呼び出されます。iOS 18では、スクロールの2~3画面先のセルに対してonAppearを呼び出すことができるプリフェッチメカニズムが導入されました — これにより知覚速度が向上しますが、不必要なネットワークリクエストが発生する可能性があります。

NavigationStackでの呼び出し動作

NavigationStack(iOS 16+)は、NavigationViewとは異なる方法で画面スタックを管理します。新しい画面をプッシュするとき、onAppearは新しい画面でのみ起動され、現在の画面は実際に削除されるまでonDisappearを受け取りません。ポップ時には逆のプロセスが発生します:離れる画面でonDisappear、戻る画面でonAppear。

シナリオonAppearonDisappear
Push新しい画面なし(画面はスタックに残る)
Pop戻る画面離れる画面
タブ切り替え新しいタブ古いタブ
シートを閉じる親画面開いていたシート

.onAppearの使用例

実用的なアプリケーションは、データロード、アニメーション開始、分析送信の3つの主要カテゴリをカバーしています。各シナリオでは、重複呼び出しやメモリリークを避けるために、SwiftUIのライフサイクル機能を考慮する必要があります。

APIからのデータロード

データロードはonAppearの最も一般的な使用例です。クロージャ内で、async呼び出し用のTaskが作成され、結果が@Stateまたは@StateObjectに保存されます。isLoadingフラグまたはnilチェックを使用して、データがすでにロードされているかどうかを確認することが重要です。

swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    
    var body: some View {
        VStack {
            if viewModel.isLoading {
                ProgressView()
            } else {
                Text(viewModel.userName)
            }
        }
        .onAppear {
            guard viewModel.userName == nil else { return }
            Task {
                await viewModel.loadProfile()
            }
        }
    }
}

再フェッチに対するガードは重要なプラクティスです。SwiftUIがViewを再作成した場合(たとえば、画面回転時)、ガードなしでonAppearが再び起動します。代替手段は.taskモディファイアで、以前のリクエストを自動的にキャンセルします。

エントリアニメーションの開始

エントリアニメーションは、withAnimationまたはanimationモディファイアを介してアニメーションをトリガーする状態変数を変更するためにonAppearを使用します。典型的なパターン:初期状態(opacity 0、offset 100)、表示時に最終状態(opacity 1、offset 0)への移行。

swift
struct AnimatedCard: View {
    @State private var isVisible = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 12)
            .fill(Color.blue)
            .opacity(isVisible ? 1 : 0)
            .offset(y: isVisible ? 0 : 50)
            .animation(.spring(), value: isVisible)
            .onAppear {
                withAnimation(.spring().delay(0.3)) {
                    isVisible = true
                }
            }
    }
}

0.3秒の遅延により、画面上に複数のカードがある場合、シーケンシャルな出現効果が生まれます。アニメーション化された要素のリストの場合、要素インデックスを遅延乗数として使用します。

.onAppear vs .task — 違い

.taskはiOS 15で追加されたSwiftUIモディファイアで、onAppearでの非同期操作の問題を解決します。onAppearとは異なり、.taskはasyncクロージャを受け入れ、そのライフサイクルを自動的に管理し、Viewが非表示になるとキャンセルします。onAppearが同期的に実行されるのに対し、.taskは非同期操作を開始し、SwiftUIがonDisappearでそれをキャンセルできるようにします。

主な違いはキャンセル管理です。.taskがasync操作を作成するとき、SwiftUIはTaskへの参照を保存し、Viewが階層から削除されると自動的にcancel()を呼び出します。内部にTask {}があるonAppearは実行中の操作をキャンセルしません — Viewが非表示になった後も実行を続け、競合状態や解放済みインスタンスへの書き込みを引き起こす可能性があります。

特性.onAppear.task
iOSバージョンiOS 13+iOS 15+
AsyncサポートTask {}経由のみネイティブasync/await
自動キャンセルなしView非表示時
再呼び出し表示のたびにデフォルトで1回
同期コードはいAsyncのみ

モディファイアの選択:同期アクション(アニメーション、分析、ログ記録)にはonAppearを使用します。非同期データロード(API、Core Data、ファイルシステム)には.taskを優先します — より安全でクリーンです。

.onAppearに関する一般的な間違い

間違い1:Viewの再作成による複数回の呼び出し。SwiftUIがViewの本文を再作成すると(状態変更、画面回転)、onAppearが再び呼び出される可能性があります。解決策 — ローディングフラグを追加するか、.equatable()を使用して不要な再描画を防ぎます。SwiftLee(2025年)によると、本番環境でのSwiftUIバグの40%はonAppearの繰り返し呼び出しに関連しています。

間違い2:強い参照によるメモリリーク。onAppearクロージャが弱い参照なしでselfをキャプチャすると、Viewとの循環参照が作成されます。SwiftUIはViewが非表示になったときにキャプチャされたオブジェクトの解放を保証しません。ViewModelやサービスの場合は、キャプチャリスト[weak self]を使用してください。

間違い3:バックグラウンドスレッドでの実行。onAppearはメインスレッドで実行されます — これはUI操作にとって正しい動作です。ただし、onAppear内でTaskを起動する場合は、@Stateの更新がMainActor.runを介して行われるようにしてください。Swift 5.9以降は自動的にMainActorに戻りますが、@MainActorを明示的に指定することをお勧めします。

繰り返し呼び出しを回避する方法

ローディングフラグを使用したパターンは、重複を防ぐ最も信頼性の高い方法です。フラグを@Stateまたは@StateObjectに保存し、手動更新時にのみリセットします。代替手段は、onAppearの代わりに.taskを使用することです:.taskは、非同期操作がすでに実行中の場合はデフォルトで再描画時に再起動しません。

swift
struct SafeView: View {
    @State private var hasAppeared = false
    @State private var items: [Item] = []
    
    var body: some View {
        List(items, id: \.id) { item in
            Text(item.name)
        }
        .onAppear {
            guard !hasAppeared else { return }
            hasAppeared = true
            Task {
                items = await DataService.shared.fetchItems()
            }
        }
    }
}

よくある質問

.onAppearはUIKitのviewDidLoadとどう違うのですか?

viewDidLoadはUIViewControllerのライフタイム中に1回呼び出され、表示状態には依存しません。.onAppearはViewが階層に追加されるたびに呼び出されます — Viewが削除されて再び追加された場合、onAppearは再び起動します。NavigationViewでは、viewDidLoadは初期化時に呼び出され、onAppearは画面が表示されるたびに呼び出されます。

.onAppear内で非同期関数を呼び出せますか?

はい、Task { await asyncFunction() }ラッパーを介して可能です。ただし、非同期操作には.taskが推奨されます。これは自動的にキャンセルを管理し、手動でTaskを作成する必要がありません。.taskはViewが非表示になったときのキャンセルも保証し、リークを防ぎます。

.onAppearが複数回呼び出されるのはなぜですか?

原因は、@State、@Published、または祖先の設定の変更によるView本文の再作成です。SwiftUIは、観測可能なプロパティの変更に応じてViewを再描画することがあります。さらに、LazyVStackとListは可視領域に近づくセルに対してonAppearを呼び出し、上にスクロールすると再び呼び出します。

.onAppearはwatchOSとtvOSで動作しますか?

はい、.onAppearはすべてのSwiftUIプラットフォームで利用可能です:iOS 13+、watchOS 6+、tvOS 13+、macOS 10.15+。動作は同じです:Viewが階層に追加されるとモディファイアが呼び出されます。watchOSでは、アプリがスタンバイ状態からアクティブになるとonAppearが起動するため、設計で考慮する必要があります。

.onAppearにパラメータを渡すにはどうすればよいですか?

.onAppearはパラメータを受け付けません — Voidクロージャのみです。パラメータを渡すには、外部変数をキャプチャするクロージャを使用します。別のアプローチとしては、ViewModifierまたは.onChangeに相当するものを介して、パラメータ付きのカスタムonAppearモディファイアを作成することです。

まとめ

  • .onAppear — Viewがインターフェース階層に追加されたときにコードを実行するSwiftUIモディファイアです。
  • 単回呼び出し — onAppearはViewがメモリに残っている場合、Viewインスタンスごとに1回呼び出されます。
  • 親優先の順序 — 親Viewは子よりも先にonAppearを受け取ります。
  • 主な使用例 — データロード、アニメーション開始、分析送信。
  • .taskが推奨 — View非表示時の自動キャンセルのため、非同期操作には.taskが推奨されます。
  • ガードチェック — View再描画時の繰り返し呼び出しを防ぐために必須です。

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

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

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

こちらもお読みください