UIViewController 的生命周期包括关键方法:
init(nibName:bundle:) / init(coder:):初始化loadView:创建视图层次结构viewDidLoad:视图已加载(适合进行初步设置的地方)viewWillAppear / viewDidAppear:视图显示/已显示viewWillDisappear / viewDidDisappear:视图隐藏/已隐藏deinit:删除控制器方法调用顺序:
loadView,然后是 viewDidLoad)viewWillAppear/viewWillDisappear,然后是 viewDidAppear/viewDidDisappeardeinit细节:
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 或代理退订,从而导致内存泄漏(NotificationCenter 引用视图控制器,导致它不会被释放并继续监听事件)。
故事
在 viewWillAppear 中,每次出现时都向视图添加新的子视图(例如,显示加载指示器),而没有检查其是否存在。结果是每次返回屏幕时都会出现更多重复的指示器,导致 UI 出现故障。