.onAppearは、Viewがインターフェース階層に追加されたときにクロージャを実行するSwiftUIモディファイアです。呼び出しは画面上のインスタンスの出現ごとに1回発生し、データのロード、アニメーションの開始、分析イベントの送信のための主要ポイントとして機能します。Apple Developer Documentation(2026年)によると、onAppearは最初のレンダリング前に実行を保証しますが、Viewがメモリに残っている場合、繰り返し表示されるたびに呼び出されることは保証しません。SwiftUIの詳細については、SwiftUIの記事をお読みください。
重要なポイント
.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。SwiftUIには優先度やアニメーションを渡す方法はありません — クロージャはレンダリング直後にメインスレッドで同期的に実行されます。
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は、layout+render段階でSwiftUIレンダリングパイプラインに組み込まれています。SwiftUIがViewの本文を計算し、階層の変更を検出すると、新しく追加されたすべてのViewに対してonAppearコールバックを起動します。呼び出し順序はネストに従います:最初に親のonAppear、次に子要素です。
SwiftUIの重要な特徴は、onAppearが物理的な画面表示に結びついていないことです。モディファイアは、Viewがユーザーに表示されるかどうかに関係なく(たとえば、ScrollViewで画面外にある場合でも)、階層に追加されると呼び出されます。これにより、viewWillAppearが実際の表示時にのみ起動するUIKitとは異なります。
呼び出し順序は親優先ルールに従います:VStackまたはNavigationViewが最初にonAppearを受け取り、次に各子要素が順番に受け取ります。これは共有リソースの初期化にとって重要です:子要素が親によってロードされたデータに依存する場合、Optionalを介して利用可能性を確認する必要があります。
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には、コンテナとナビゲーションに依存するいくつかの呼び出しシナリオがあります。NavigationStackでは、onAppearは新しいコントローラのプッシュごと、およびポップ時にルートコントローラに対して起動されます。TabViewでは、タブの切り替えにより、表示されているタブにonAppearが、非表示のタブにonDisappearが呼び出されます。
ListおよびScrollViewでは、可視領域に入ったセルまたはプリレンダリングバッファ内のセルに対してonAppearが呼び出されます。iOS 18では、スクロールの2~3画面先のセルに対してonAppearを呼び出すことができるプリフェッチメカニズムが導入されました — これにより知覚速度が向上しますが、不必要なネットワークリクエストが発生する可能性があります。
NavigationStack(iOS 16+)は、NavigationViewとは異なる方法で画面スタックを管理します。新しい画面をプッシュするとき、onAppearは新しい画面でのみ起動され、現在の画面は実際に削除されるまでonDisappearを受け取りません。ポップ時には逆のプロセスが発生します:離れる画面でonDisappear、戻る画面でonAppear。
| シナリオ | onAppear | onDisappear |
|---|---|---|
| Push | 新しい画面 | なし(画面はスタックに残る) |
| Pop | 戻る画面 | 離れる画面 |
| タブ切り替え | 新しいタブ | 古いタブ |
| シートを閉じる | 親画面 | 開いていたシート |
実用的なアプリケーションは、データロード、アニメーション開始、分析送信の3つの主要カテゴリをカバーしています。各シナリオでは、重複呼び出しやメモリリークを避けるために、SwiftUIのライフサイクル機能を考慮する必要があります。
データロードはonAppearの最も一般的な使用例です。クロージャ内で、async呼び出し用のTaskが作成され、結果が@Stateまたは@StateObjectに保存されます。isLoadingフラグまたはnilチェックを使用して、データがすでにロードされているかどうかを確認することが重要です。
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)への移行。
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秒の遅延により、画面上に複数のカードがある場合、シーケンシャルな出現効果が生まれます。アニメーション化された要素のリストの場合、要素インデックスを遅延乗数として使用します。
.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を優先します — より安全でクリーンです。
間違い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は、非同期操作がすでに実行中の場合はデフォルトで再描画時に再起動しません。
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()
}
}
}
}
よくある質問
viewDidLoadはUIViewControllerのライフタイム中に1回呼び出され、表示状態には依存しません。.onAppearはViewが階層に追加されるたびに呼び出されます — Viewが削除されて再び追加された場合、onAppearは再び起動します。NavigationViewでは、viewDidLoadは初期化時に呼び出され、onAppearは画面が表示されるたびに呼び出されます。
はい、Task { await asyncFunction() }ラッパーを介して可能です。ただし、非同期操作には.taskが推奨されます。これは自動的にキャンセルを管理し、手動でTaskを作成する必要がありません。.taskはViewが非表示になったときのキャンセルも保証し、リークを防ぎます。
原因は、@State、@Published、または祖先の設定の変更によるView本文の再作成です。SwiftUIは、観測可能なプロパティの変更に応じてViewを再描画することがあります。さらに、LazyVStackとListは可視領域に近づくセルに対してonAppearを呼び出し、上にスクロールすると再び呼び出します。
はい、.onAppearはすべてのSwiftUIプラットフォームで利用可能です:iOS 13+、watchOS 6+、tvOS 13+、macOS 10.15+。動作は同じです:Viewが階層に追加されるとモディファイアが呼び出されます。watchOSでは、アプリがスタンバイ状態からアクティブになるとonAppearが起動するため、設計で考慮する必要があります。
.onAppearはパラメータを受け付けません — Voidクロージャのみです。パラメータを渡すには、外部変数をキャプチャするクロージャを使用します。別のアプローチとしては、ViewModifierまたは.onChangeに相当するものを介して、パラメータ付きのカスタムonAppearモディファイアを作成することです。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。