viewWillAppear — 是 UIViewController 的一个方法,UIKit 在屏幕对用户可见之前每次都会调用它。根据 Apple Developer Documentation,这个方法接收一个布尔参数 animated,指示转换是否伴随动画。viewWillAppear — 是更新数据和同步屏幕状态的主要位置。
要点
viewWillAppear — 是 UIViewController 的一个方法,UIKit 在将 View 添加到窗口层次结构之前立即调用。此时,View 在经过 Auto Layout 后已有最终尺寸,但对用户尚不可见 — 过渡动画要么尚未开始,要么正在执行。开发者重写此方法以执行每次屏幕显示前应发生的操作。
与只执行一次的 viewDidLoad 不同,viewWillAppear 在屏幕即将出现时每次都被调用:在初始打开时、从子控制器返回时、关闭模态窗口后以及在切换 TabBar 标签时。这使其成为维护界面最新状态的关键方法。
该方法接收 Bool 类型的 animated 参数,如果屏幕出现伴随动画则为 true。此参数便于传递给具有类似参数的 NavigationBar 和 TabBar 方法,以实现一致的行为。
时机 viewWillAppear 的调用取决于导航类型,但一般规则不变:该方法在 View 变为可见之前执行。让我们看看主要场景。
在调用 viewDidLoad 后,UIKit 开始准备显示:View 被添加到层次结构中,执行 layout 步骤,然后就在过渡动画开始之前调用 viewWillAppear。此时屏幕尚不可见,但所有子视图都有正确的尺寸,可以安全地更新其内容。
当用户按下返回按钮或以编程方式调用 popViewController 时,UIKit 返回到上一个屏幕并调用其 viewWillAppear。这是使用 viewWillAppear 的主要场景 — 在添加元素后更新列表或同步设置。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
updateBadgeCount()
}
在关闭以模态方式呈现的控制器后,UIKit 在呈现该控制器的控制器上调用 viewWillAppear。如果您使用委托或闭包来回传数据,此场景需要特别注意 — viewWillAppear 确保屏幕在收到结果后更新。
TabBarController 在每次切换时调用所选标签控制器的 viewWillAppear。如果标签上显示动态数据 — 汇率、通知、用户状态 — viewWillAppear 是更新它们的理想位置。
viewWillAppear 解决了一些在其他方法中无法执行或不是最优的具体任务。让我们看看主要的。
viewWillAppear 最常见的用途 — 在每次屏幕出现时重新加载UITableView 或 UICollectionView。如果数据在上一个屏幕上可能已更改(添加元素、更改状态),在 viewWillAppear 中调用 reloadData 可确保用户看到最新信息。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
viewModel.synchronize()
tableView.reloadData()
}
在 viewWillAppear 中可以方便地配置 NavigationBar 的外观:隐藏或显示、更改颜色、设置 large title。如果 NavigationBar 在不同屏幕上看起来不同,viewWillAppear 是进行这些更改的正确位置,因为 viewDidLoad 只调用一次。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(
false, animated: animated
)
navigationController?.navigationBar.prefersLargeTitles = true
tabBarController?.tabBar.isHidden = false
}
仅在屏幕可见时才有意义的通知 — 键盘通知、内容更改通知 — 在 viewWillAppear 中订阅并在 viewDidDisappear 中取消订阅。这可以防止屏幕不活跃时的不必要的处理器,并防止内存泄漏。
如果屏幕可能被应用程序隐藏或最小化,viewWillAppear 是恢复 UI 状态的便捷位置:切换段、恢复滚动位置、重置临时更改。用户每次出现时都以可预测的形式获得屏幕。
在显示未读消息、评分或通知计数器的屏幕上,viewWillAppear 是更新它们的正确位置。如果用户可能在另一个屏幕上更改了数量,这里调用重新计算并更新UITabBarItem.badgeValue 或自定义指示器。这确保用户无论在其他屏幕上停留多久,始终看到最新的数字。
单独提一下 collectionView 的工作:如果屏幕上的数据以包含计数器或状态的单元格网格形式呈现,它们在 viewWillAppear 中的更新应该是选择性的。不要完全 reloadData,而是对可见单元格使用 reloadItemsAtIndexPaths,以避免闪烁和丢失滚动位置。
理解 viewWillAppear 和 viewDidLoad 之间的区别 — 正确 UIViewController 架构的基础。这两种方法具有不同的调用频率、不同的上下文和不同的目的。
viewDidLoad 被调用一次,适用于不随时间变化的配置:注册单元格、设置委托、初始化常量。viewWillAppear 在每次出现时被调用,适用于需要重复的操作:更新数据、配置可见元素、同步状态。
| 特征 | viewDidLoad | viewWillAppear |
|---|---|---|
| 频率 | 一次 | 每次出现时 |
| View 可见 | 否 | 否(即将可见) |
| View 尺寸 | 非最终 | 最终 |
| 适用于 | 一次性配置 | 更新和同步 |
| 动画 | 不适用 | animated 参数 |
黄金规则:如果操作只应执行一次 — 放在 viewDidLoad 中。如果每次返回屏幕时都应重复 — 放在 viewWillAppear 中。
错误使用 viewWillAppear 可能导致性能问题、过度更新和界面状态不一致。让我们看看最常见的错误。
第一个错误 — 重复 viewDidLoad 中的逻辑。如果您同时注册表格单元格在 viewDidLoad 和 viewWillAppear 中 — 注册将多次执行,而一次性配置就足够了。将所有一次性配置移到 viewDidLoad 中。
第二个错误 — 每次出现时无条件 reloadData。如果数据没有更改,重新加载表格会导致额外的数据源请求和重绘单元格,降低性能。在调用 reloadData 之前检查状态是否真的发生了变化。
第三个错误 — 处理网络请求时没有考虑到屏幕可能在请求完成前再次被隐藏。如果您在 viewWillAppear 中启动 URLSession 请求,而用户立即转到另一个屏幕,结果可能被应用到已隐藏的 View。使用可取消的任务或在更新前检查 isViewLoaded 和 window。
第四个错误 — 忘记调用 super。不调用 super.viewWillAppear 可能会破坏父控制器(UINavigationController、UITabBarController)的功能,并导致手势和转换的错误处理。super 应该始终被调用。
第五个错误 — 在不调用 layoutIfNeeded 的情况下更改约束。如果在 viewWillAppear 中以编程方式更改约束,UIKit 不会立即应用它们 — 更改会累积到下一次 layout 步骤。要在修改约束后立即应用更改,调用 view.layoutIfNeeded()。这在设置依赖于内容高度的元素时尤为重要。
第六个错误 — 尝试在 viewWillAppear 中执行动画。如上所述,UIKit 仍在处理过渡动画,您的动画可能会与系统动画竞争。如果您需要元素以效果出现,在 viewDidAppear 中使用入场动画,在 viewWillAppear 中只配置初始状态:透明 0,缩放变换 0.8 等。
第七个错误 — 忽略 animated 参数。一些开发者不检查 viewWillAppear 中的 animated 值,并执行应该取决于动画是否存在的操作。例如,在 animated = false 时可以无动画隐藏 NavigationBar,而在 animated = true 时带动画隐藏,以使过渡看起来平滑。始终将 animated 参数传递给相应的 UIKit 方法。
第八个错误 — 在不可见的屏幕上修改 UI。如果在 viewWillAppear 中启动网络请求,并且当屏幕可能已消失时其完成块更新 UI,用户将看到闪烁或不一致的状态。始终在 closures 中更新 UI 之前检查 isViewLoaded 和 window。这个简单的操作可以防止崩溃和不必要的界面重绘。
常见问题
viewWillAppear 在出现动画开始之前被调用,此时 View 尚不可见。viewDidAppear — 在动画结束后,当屏幕完全显示且可用于交互时被调用。
在正常条件下,viewWillAppear 在屏幕出现时总是被调用。例外 — 强制退出应用程序(force quit),此时 UIKit 来不及调用 Lifecycle 方法。
是的,必须。UIKit 使用此调用与 UINavigationController 和 UITabBarController 进行内部协调。没有 super,手势和过渡动画可能会损坏。
每次切换标签时。UIKit 在用户点击 TabBar 中相应图标后立即在所选标签控制器上调用 viewWillAppear。
使用控制器的属性或共享数据源。在调用 popViewController 之前,在前一个控制器上设置所需的值,在其 viewWillAppear 中它们已经可用。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。