viewDidLoadは、UIKitがUIViewControllerのViewをメモリにロードした後に呼び出す最初のメソッドです。Apple Developer Documentationによると、このメソッドはコントローラの存続期間中に正確に1回だけ呼び出されます。viewDidLoadは、インターフェースの初期設定、セルの登録、データの初期化を行うための主要な場所です。
重要なポイント
viewDidLoadはUIViewControllerのインスタンスメソッドで、UIKitがコントローラのViewをメモリにロードした直後に呼び出します。この時点では、すべてのIBOutletプロパティはすでにインターフェース要素に接続されていますが、Viewはまだウィンドウ階層に追加されておらず、ユーザーには表示されていません。開発者はこのメソッドをオーバーライドして、画面の初期設定を実行します。
このメソッドはViewController Lifecycleの一部であり、Viewがプログラムで作成された場合はloadViewの直後、またはStoryboardからのロード後に続きます。一般的なプロジェクトでは、viewDidLoadはUIViewControllerの最も頻繁にオーバーライドされるメソッドであり、すでに存在して設定準備が整っているサブビューを操作するための安全なポイントを提供します。
重要な詳細:viewDidLoadが呼び出される時点では、Viewの寸法はまだ最終的なものに対応していません — Auto Layoutがパスを完了しておらず、フレームが期待と異なる場合があります。寸法に依存する計算には、viewDidLayoutSubviewsを使用してください。
viewDidLoad呼び出しのタイミングは、コントローラがどのように初期化されるかによって異なります。ほとんどの場合、UIKitはコントローラのviewプロパティに初めてアクセスされたときにこのメソッドを自動的に呼び出します — これはUIViewControllerのlazy-loadingメカニズムと呼ばれます。
NavigationControllerまたはTabBarControllerが初めて画面を表示するとき、UIKitはViewがロードされているかどうかを確認します。ロードされていない場合 — loadViewが呼び出され(またはStoryboardからのロード)、その直後にviewDidLoadがトリガーされます。これは標準的なシナリオであり、各コントローラインスタンスに対して1回発生します。
override func viewDidLoad() {
super.viewDidLoad()
print("Viewがロードされました — インターフェースを設定できます")
setupUI()
configureTableView()
}
戻るボタンやdismissを介して画面に戻っても、viewDidLoadは再度呼び出されません。ロジックが画面の再表示に依存する場合 — viewWillAppearに配置してください。これは最も一般的な概念的な誤りの1つです:開発者はviewDidLoadが表示のたびに動作することを期待しますが、UIKitはそれを1回だけ呼び出します。
開発者は、事前にロードをトリガーするためにコントローラのviewに強制的にアクセスすることがあります:let _ = controller.view。これにより、コントローラが画面に表示される前にloadViewとviewDidLoadが強制的に呼び出されます。このテクニックは、スムーズな遷移のために事前にViewを準備する必要がある場合に使用されます。
viewDidLoadは、画面が表示されているかどうかに依存しない1回限りの設定操作を目的としています。このメソッドの適切な使用は、クリーンなアーキテクチャと予測可能なコントローラ動作の鍵です。
viewDidLoadでは、UITableViewやUICollectionViewのnibファイルやクラスを登録し、デリゲートを設定し、UI要素のプロパティの初期値を設定します。この時点ですべてのIBOutletがすでに接続されているため、label.text、imageView.image、その他のサブビュープロパティに安全にアクセスできます。
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(
CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier
)
title = "メイン画面"
}
ここでviewModelを作成し、配列でdata sourceを初期化し、コントローラの存続期間中アクティブであるべき通知を購読します。たとえば、バックグラウンドから戻ったときにデータを更新するためのUIApplication.willEnterForegroundNotificationの購読は、viewDidLoadの良い候補です。現代のiOSアーキテクチャにおけるviewModelは、コントローラとビジネスロジックの間のブリッジとして機能し、viewDidLoadで初期化することで、画面が最初に表示されるまでにデータの準備が整います。
テーブルとコレクションのdata sourceの設定には特に注意してください。テーブルがCore DataでUIFetchedResultsControllerまたはNSFetchedResultsControllerを使用する場合、viewDidLoadでfetch requestとデリゲートを初期化してください。これにより、画面が最初に表示される際に、追加のリクエストなしでテーブルがすでにデータで埋められていることが保証されます。
viewDidLoadでは、NavigationBarのボタンを設定し、large titleを設定し、search controllerを追加し、edit/doneボタンを設定します。これらの要素は画面が再度表示されても変更されることはほとんどないため、ここで初期化するのが最適です。
すべての操作がviewDidLoadに適しているわけではありません。このメソッドに配置された一部のアクションは、過剰なメモリ消費、誤った動作、または画面の再表示時のバグを引き起こします。
避けるべきこと:結果がUIにのみ影響するネットワークリクエストの開始。リクエストが画面表示前に完了した場合、ユーザーは結果を見ることができず、後に完了した場合 — データが古くなっている可能性があります。viewDidLoadでロードを開始しますが、UIはviewWillAppearで更新してください。
してはいけないこと:Viewのサイズや位置に依存する操作をviewDidLoadで行うこと。呼び出し時点では、Auto Layoutがパスを完了しておらず、フレームが最終的でない可能性があります。計算にはviewDidLayoutSubviewsを使用するか、updateViewConstraintsをオーバーライドしてください。
購読してはいけないこと:画面が表示されているときにのみ関連する通知。キーボード通知、子コントローラからのコンテンツ変更通知 — これらはviewWillAppearで購読し、viewDidDisappearで購読解除して、不要な呼び出しやリークを避けてください。
呼び出してはいけないこと:表示画面を必要とするメソッド。たとえば、viewDidLoadからUIAlertControllerを表示しようとすると、コントローラのViewがまだウィンドウ階層に追加されていないためエラーが発生します。ウィンドウやpresentedViewControllerに依存するUI操作は、画面が表示された後にのみ実行する必要があります。
初期化してはいけないこと:不必要な重いリソース。画面がめったに表示されない場合やデータがすぐに表示されない場合、リソースを多く消費するオブジェクトの作成は実際に必要になるまで延期してください。Swiftの遅延プロパティ初期化は、この問題を解決するための組み込みメカニズムです:lazy修飾子を持つプロパティは最初のアクセス時にのみ作成され、メモリを節約し画面の読み込みを高速化します。
使用してはいけないこと:画面が表示されるたびに実行されるべき操作にviewDidLoadを使用すること。これが最も基本的な誤りです:初心者の開発者はしばしばデータ更新ロジックをviewDidLoadに配置し、別の画面から戻ったときにテーブルがリロードされないことに驚きます。操作が表示のたびに繰り返されるべき場合 — viewWillAppearを使用してください。存続期間中に1回実行されるべき場合 — viewDidLoadを使用してください。UIViewControllerのライフサイクルに関するほとんどの問題を避けるために、このシンプルなルールを覚えておいてください。
実際のプロジェクトでのviewDidLoadの正しい使用法を示す3つの実践的な例を見てみましょう。各例は特定の画面設定タスクを解決します。
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(
PhotoCell.self,
forCellWithReuseIdentifier: PhotoCell.reuseId
)
collectionView.register(
HeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: HeaderView.reuseId
)
viewModel.delegate = self
viewModel.fetchInitialPage()
}
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
label.text = "こんにちは、世界!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
viewDidLoadでは、データがないときに表示される要素(空の状態、ローダー、プレースホルダー)も設定します。これらのコンポーネントは1回作成され、画面が表示されるたびに再利用されます。これらの要素の表示/非表示は、現在のデータに応じてviewWillAppearで管理されます。
override func viewDidLoad() {
super.viewDidLoad()
emptyStateLabel = UILabel()
emptyStateLabel.text = "データがありません"
emptyStateLabel.textAlignment = .center
emptyStateLabel.isHidden = true
view.addSubview(emptyStateLabel)
activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
@objc private func handleEnterForeground() {
refreshContent()
}
よくある質問
通常の状態では、いいえ — UIKitはViewをメモリにロードした後、viewDidLoadを1回呼び出します。コントローラが破棄されて再作成された場合、新しいインスタンスに対してviewDidLoadが実行されます。
はい、必須です。super.viewDidLoadを呼び出すことで、UIKitがLifecycleを正しく機能させるために必要な内部設定を実行することが保証されます。メソッド内で常に最初にsuperを呼び出してください。
viewDidLoadはViewのロード時に1回呼び出されます。viewWillAppearは画面が表示される前に毎回呼び出されます。前者は1回限りの設定用、後者はデータと状態の更新用です。
viewDidLoadでの重い同期処理はメインスレッドをブロックし、画面表示を遅らせます。非同期ロードは許容されますが、完了時にUIを更新する際には、画面がすでに非表示になっている可能性を考慮する必要があります。
viewDidLoadを直接呼び出すことはできません — UIKitが呼び出します。Viewのロードを強制するには、controller.viewプロパティにアクセスしてください。これによりloadViewとviewDidLoadが自動的にトリガーされます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。