iOS 子控制器容器化设计
iOS 子控制器容器化设计
复杂页面常由顶部摘要、标签页、列表和浮动操作区组成。把所有逻辑放进一个控制器,会让生命周期、布局和状态处理迅速膨胀。子控制器容器化可以拆分职责,但必须正确转发生命周期、建立视图层级,并明确父子之间的通信边界。
一、何时使用子控制器
适合拆成子控制器的区域通常具备:
- 独立的数据与交互逻辑。
- 相对稳定的视图边界。
- 需要独立生命周期回调。
- 可能在多个容器中复用。
只有几行静态展示的区域,用普通子视图更简单。控制器拆分应围绕行为边界,而不是每个视觉块都创建一层。
二、正确添加子控制器
func embed(
child: UIViewController,
in containerView: UIView
) {
addChild(child)
containerView.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: containerView.topAnchor),
child.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
child.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
])
child.didMove(toParent: self)
}
顺序表达了完整容器协议:先建立父子关系,再添加视图,最后通知迁移完成。
三、正确移除子控制器
func remove(child: UIViewController) {
child.willMove(toParent: nil)
child.view.removeFromSuperview()
child.removeFromParent()
}
移除后,父控制器还要清理自己持有的强引用和回调。如果子控制器有长期观察或任务,也应在自身生命周期内停止。
四、让父级承担流程协调
子控制器不应直接引用兄弟控制器。父级接收筛选条件,再把新状态传给列表:
protocol FilterChildDelegate: AnyObject {
func filterChild(
_ child: FilterViewController,
didSelect condition: FilterCondition
)
}
extension DashboardViewController: FilterChildDelegate {
func filterChild(
_ child: FilterViewController,
didSelect condition: FilterCondition
) {
viewModel.updateFilter(condition)
}
}
父级协调让数据流保持单向,也避免两个子模块互相持有。
五、共享状态而不是复制状态
多个子控制器展示同一页面状态时,可以观察同一个页面模型,或由父级把不可变展示模型分别传入。不要让每个子控制器各自请求同一份数据并维护副本。
共享引用模型需要明确谁创建和持有,子控制器只观察,不负责重置全局状态。
六、标签页切换与懒加载
标签页可以在首次选中时创建子控制器,减少首屏成本。创建后是否保留取决于页面数量和内存:
- 少量高频页面可以保留,切换更快。
- 大量重型页面可以在离开后释放,再保存最小恢复状态。
延迟创建不能让首次点击出现明显主线程卡顿。重型数据加载仍应异步进行。
七、处理外观生命周期
系统在标准容器关系中通常会转发外观回调。自定义转场、同时显示多个子页面或手动控制视图出现时,需要确认转发行为是否符合预期。
不要仅为了触发统计而手动调用子控制器的生命周期方法。需要自定义转发时,应使用系统提供的外观转换协议,并保持成对调用。
八、布局和安全区域
子控制器视图边界由容器决定,内部内容可以继续相对自身安全区域或布局边距。父级的固定栏遮挡子内容时,应通过额外安全区域或明确内容内边距处理,而不是让每个子页面写死高度。
键盘、横屏和多任务尺寸变化也要在父子两层验证。
九、导航职责
子控制器可以报告“用户选择了某项”,由父级或协调器决定如何导航。这样子模块不依赖特定导航栈,也能在弹窗、标签页等不同容器复用。
需要子模块自己管理内部导航时,可以让它拥有独立导航容器,但跨模块出口仍由稳定协议表达。
十、测试容器关系
重点验证:
- 添加后父子关系和视图约束正确。
- 替换页面时旧控制器能够释放。
- 标签切换不会重复创建或重复请求。
- 子事件只由父级处理一次。
- 横竖屏和安全区域变化时布局正确。
- 外观统计不会漏报或重复。
总结
子控制器容器化的价值是拆分行为和生命周期。严格遵守添加与移除协议,由父级协调子组件通信,共享单一页面状态,并根据真实成本决定懒加载与释放。这样复杂页面既能分治,也不会产生隐藏的层级和生命周期问题。
- 点赞
- 收藏
- 关注作者
评论(0)