iOS中的viewDidLoad:是什么、用途及代码示例

作者: IT Sectr 发布日期: 2026-03-05 阅读时间: 8 分钟

viewDidLoad — 是UIKit在将UIViewController的View加载到内存后调用的第一个方法。根据Apple Developer Documentation,这个方法在控制器的整个生命周期中只被调用一次。viewDidLoad是进行界面初始配置、注册单元格和初始化数据的主要位置。

要点

  • viewDidLoad在View加载到内存后被调用一次
  • super.viewDidLoad是必需的——没有它Lifecycle会出问题
  • 在此方法中配置UI、注册单元格和创建data source
  • 返回屏幕时不会再次调用——请使用viewWillAppear
  • 适用于一次性操作和订阅永久通知

什么是viewDidLoad

viewDidLoad — 是UIViewController的一个实例方法,UIKit在控制器的View加载到RAM后立即调用它。此时,所有IBOutlet属性已经连接到界面元素,但View尚未添加到窗口层次结构中,对用户不可见。开发者重写此方法以执行屏幕的初始配置。

该方法是ViewController Lifecycle的一部分,如果View是以编程方式创建的,则紧随loadView之后,或者从Storyboard加载后立即执行。在典型项目中,viewDidLoad是UIViewController最常被重写的方法,因为它提供了一个安全点来操作已经存在且准备配置的subviews。

一个重要细节:在调用viewDidLoad时,View的尺寸尚不符合最终尺寸——Auto Layout尚未完成传递,frame可能与预期不同。对于依赖于尺寸的计算,应使用viewDidLayoutSubviews

什么时候调用viewDidLoad

viewDidLoad的调用时机取决于控制器的初始化方式。在大多数情况下,UIKit在第一次访问控制器的view属性时自动调用此方法——这称为UIViewController的lazy-loading机制。

首次打开屏幕时

当NavigationController或TabBarController首次显示您的屏幕时,UIKit检查View是否已加载。如果没有——则调用loadView(或从Storyboard加载),之后立即触发viewDidLoad。这是标准场景,每个控制器实例只发生一次。

swift
override func viewDidLoad() {
    super.viewDidLoad()
    print("View已加载——可以配置界面")
    setupUI()
    configureTableView()
}

返回现有屏幕时

viewDidLoad不会再次调用通过back按钮或dismiss返回屏幕时。如果您的逻辑依赖于屏幕再次出现——请将其放在viewWillAppear中。这是最常见的概念错误之一:开发者期望viewDidLoad在每次显示时触发,但UIKit只调用它一次。

在forcedViewLoad时

有时开发者强制调用控制器的view以提前启动加载:let _ = controller.view。这强制在控制器出现在屏幕之前调用loadView和viewDidLoad。当需要提前准备View以实现平滑过渡时,会使用这种技巧。

在viewDidLoad中做什么

viewDidLoad旨在执行不依赖于屏幕是否可见的一次性配置操作。正确使用此方法是实现清晰架构和控制器可预测行为的关键。

配置UI组件

在viewDidLoad中注册UITableView和UICollectionView的nib文件和类,配置委托,设置UI元素属性的初始值。由于此时所有IBOutlet都已连接,可以安全地访问label.text、imageView.image和其他subviews属性。

swift
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的合适候选。ViewModel在现代iOS架构中充当控制器和业务逻辑之间的桥梁,在viewDidLoad中初始化它可确保在屏幕首次出现时数据已经准备就绪。

特别关注表格和集合的data source配置。如果您的表格使用Core Data的UIFetchedResultsController或NSFetchedResultsController,请在viewDidLoad中初始化fetch request和委托。这保证了在屏幕首次出现时,表格无需额外查询就已填充数据。

配置导航

在viewDidLoad中配置NavigationBar按钮、设置large title、添加search controller和设置edit/done按钮。这些元素在屏幕重复显示时很少更改,因此在此处初始化它们是最优的

在viewDidLoad中不应该做什么

并非所有操作都适合在viewDidLoad中执行。放置在此方法中的某些操作会导致内存过度消耗、行为异常或屏幕重复显示时的错误。

避免启动仅影响UI的网络请求。如果请求在屏幕出现之前完成,用户将看不到结果,如果在之后完成——数据可能已过时。在viewDidLoad中启动加载,但在viewWillAppear中更新UI。

不要在viewDidLoad中执行依赖于View尺寸和位置的操作。在调用时,Auto Layout尚未完成传递,frame可能不是最终的。对于计算,请使用viewDidLayoutSubviews或重写updateViewConstraints。

不要订阅仅在屏幕可见时才起作用的通知。键盘通知、子控制器内容变更通知——在viewWillAppear中订阅并在viewDidDisappear中取消订阅,以避免不必要的调用和内存泄漏。

不要调用需要可见屏幕的方法。例如,从viewDidLoad尝试显示UIAlertController将导致错误,因为控制器的View尚未添加到窗口层次结构。所有依赖于window或presentedViewController的UI操作只能在屏幕出现后执行。

不要初始化不必要的重量级资源。如果屏幕很少打开或数据不立即显示,请将创建资源密集型对象推迟到真正需要时。Swift中的属性懒初始化是解决此任务的内置机制:带有lazy修饰符的属性仅在第一次访问时才创建,从而节省内存并加速屏幕加载。

不要使用viewDidLoad执行应在每次屏幕显示时执行的操作。这是最基本的错误:初级开发者经常将数据更新逻辑放在viewDidLoad中,然后奇怪为什么从其他屏幕返回时表格没有重新加载。如果操作应在每次显示时重复——使用viewWillAppear。如果在生命周期内只应执行一次——使用viewDidLoad。记住这个简单规则,以避免UIViewController生命周期相关的大部分问题。

viewDidLoad代码示例

让我们来看三个实际示例,展示viewDidLoad在真实项目中的正确使用。每个示例解决一个具体的屏幕配置任务。

示例1:配置自定义单元格的集合

swift
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()
}

示例2:以编程方式配置约束

swift
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)
    ])
}

示例3:配置空状态和加载器

在viewDidLoad中还配置了在无数据时显示的元素:空状态、加载器、占位符。这些组件创建一次并在每次屏幕显示时重复使用。这些元素的隐藏或显示根据当前数据在viewWillAppear中控制。

swift
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)
}

示例4:订阅应用通知

swift
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(handleEnterForeground),
        name: UIApplication.willEnterForegroundNotification,
        object: nil
    )
}

@objc private func handleEnterForeground() {
    refreshContent()
}

常见问题

viewDidLoad能被调用多次吗?

正常情况下不会——UIKit在View加载到内存后调用一次viewDidLoad。如果控制器被销毁并重新创建,viewDidLoad将为新实例执行。

是否需要调用super.viewDidLoad?

是的,必须调用。调用super.viewDidLoad确保UIKit执行正确运行Lifecycle所需的内部配置。始终在方法中首先调用super。

viewDidLoad和viewWillAppear之间的区别是什么?

viewDidLoad在View加载时调用一次。viewWillAppear在每次屏幕出现之前调用。前者用于一次性配置,后者用于更新数据和状态。

可以在viewDidLoad中执行重量级操作吗?

viewDidLoad中的重量级同步操作会阻塞主线程并延迟屏幕出现。异步加载是允许的,但在完成更新UI时需要注意屏幕可能已经隐藏。

如何强制调用viewDidLoad?

不能直接调用viewDidLoad——它由UIKit调用。要强制加载View,请访问controller.view属性。这将自动触发loadView和viewDidLoad。

总结

  • viewDidLoad — View加载到内存后UIViewController的一次性配置方法
  • 在第一次访问View时,在控制器生命周期中调用一次
  • 适用于注册单元格、配置委托、初始化viewModel
  • 始终调用super.viewDidLoad以确保Lifecycle正确运行
  • 不要将viewDidLoad用于依赖于View尺寸的操作
  • 每次出现时更新数据请使用viewWillAppear
  • 订阅永久通知——合适;临时通知——在viewWillAppear中

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读