UIKit 中被隐藏的视图是否会对应用内存造成压力?
问题描述
我有一个父视图存在多种不同状态,分别对应展示等待动画、倒计时、录制界面等场景,每个状态都对应父视图的一个直接子视图:
我的实现思路是定义一个状态变量,通过属性观察器来仅展示对应状态的子视图,示例代码如下:
enum Status { case waiting case countDown // ... } var status: Status = .loading { didSet { showRelevantView() } } func showRelevantView() { waitingView.isHidden = status != .waiting countDownView.isHidden = status != .countDown // ... }
按照上述逻辑实现后,6个子视图同一时间只会有1个处于展示状态,其余5个均被设置为隐藏。我想了解这5个被隐藏的子视图是否会对应用内存造成压力,如果存在内存问题,有什么合适的优化方案?
解答
隐藏视图的内存占用说明
- 只要子视图还被强引用持有、且保留在父视图的层级中,哪怕设置了
isHidden = true,依旧会占用内存 - 如果你的6个子视图都是轻量视图(仅包含普通文本、按钮、小尺寸图标),总内存占用通常只有几KB到几十KB,完全不会造成内存压力,现有实现无需修改
- 如果部分子视图包含大尺寸资源、视频预览层、实时动画、大量渲染图层,隐藏状态下这些资源依旧会驻留内存,累计下来可能造成不必要的内存占用,就需要做优化
常用优化方案
- 方案1:按需添加/移除视图(最通用)
不要提前初始化所有子视图并添加到父视图,仅在状态切换时做如下操作:
// 记录当前正在展示的视图 private weak var currentShowingView: UIView? func showRelevantView() { // 先移除当前正在展示的旧视图 currentShowingView?.removeFromSuperview() // 根据状态获取对应视图,不常用的视图可以设为懒加载,首次使用才初始化 var targetView: UIView? switch status { case .waiting: targetView = waitingView case .countDown: targetView = countDownView // ...其他状态处理 default: break } guard let targetView = targetView else { return } // 添加新视图到父视图 parentView.addSubview(targetView) // 适配布局,这里以SnapKit为例,也可以用frame或系统约束 targetView.snp.makeConstraints { make in make.edges.equalToSuperview() } currentShowingView = targetView }
- 方案2:子控制器拆分管理
如果每个状态对应的业务逻辑比较复杂,可以把每个状态的视图和逻辑封装到独立的UIViewController中,通过父控制器的子控制器管理API来控制生命周期,逻辑拆分更清晰,系统会自动触发子控制器的生命周期回调:
private weak var currentChildVC: UIViewController? func showRelevantController() { // 移除旧的子控制器 currentChildVC?.willMove(toParent: nil) currentChildVC?.view.removeFromSuperview() currentChildVC?.removeFromParent() // 加载对应新的子控制器 let targetVC = // 根据状态获取对应子控制器实例 addChild(targetVC) view.addSubview(targetVC.view) targetVC.view.snp.makeConstraints { make in make.edges.equalToSuperview() } targetVC.didMove(toParent: self) currentChildVC = targetVC }
- 方案3:缓存池方案(适合频繁切换场景)
如果状态切换非常频繁,每次创建销毁视图开销过大,可以维护一个最大容量的缓存池,缓存最近使用的2-3个视图,超出容量的视图自动释放,平衡内存占用和加载速度。
内容的提问来源于stack exchange,提问作者Dannis Case
相关产品推荐
相关产品推荐

