UIViewControllerのライフサイクルには、以下の重要なメソッドが含まれます:
init(nibName:bundle:) / init(coder:): 初期化loadView: ビューの階層を作成viewDidLoad: ビューがロードされた(初期設定に最適な場所)viewWillAppear / viewDidAppear: ビューが表示される/表示されたviewWillDisappear / viewDidDisappear: ビューが非表示になる/非表示になったdeinit: コントローラーの削除メソッドの呼び出し順序:
loadView の後に viewDidLoad)viewWillAppear/viewWillDisappear が呼び出され、その後 viewDidAppear/viewDidDisappear が呼び出されるdeinit注意点:
viewDidLoad ではビューのサイズにアクセスしない方が良い — 不正確な場合があるためdeinit または viewWillDisappear で解放することが重要viewDidLoad で行い、viewWillAppear では行わないこと — 各表示時に重複する可能性があるため例:
class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setupViews() setupBindings() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 通知に登録 } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 通知から登録解除 } deinit { // クリーンアップ } }
質問:
ビューコントローラーはライフサイクルの外でビューのプロパティにアクセスしても良いですか(例えば、初期化子内で)?
回答:
いいえ、loadView が呼び出される(またはオーバーライドされる)前は、ビューに関連するすべてのプロパティが初期化されていない可能性があります。loadView/viewDidLoad の外でのアクセスはクラッシュを引き起こします。
例:
// エラー: self.view はまだ初期化されていません! init() { super.init(nibName: nil, bundle: nil) self.view.backgroundColor = .red //クラッシュ }
物語
プロジェクトは初期化時にself.viewに過剰にアクセスするためにクラッシュしました—ビュ―は作成されておらず、クラッシュにつながりました。
物語
大規模なプロジェクトでは、viewWillDisappear または deinit で NotificationCenter や delegate からの登録解除を忘れ、メモリリークを引き起こすことがありました(NotificationCenter がビューコントローラーを参照し、解放されずイベントを聞き続ける)。
物語
viewWillAppear では、各表示のたびにビューに新しいサブビュー(例えば、読み込みインジケーター)を追加し、存在を確認しませんでした。その結果、画面に戻るたびに重複するインジケーターが増え、UIが機能しなくなる事態を招きました。