iOS中如何从父视图控制器检测ViewDidDisappear事件
嘿,我完全懂你说的这种痛点——直接在子控制器里硬编码调用父控制器的方法确实不够灵活,耦合性太高了,换个父控制器就得改代码,太麻烦。这里有几种更优雅的方案,帮你实现父控制器监听子控制器的viewDidDisappear事件:
方案1:代理模式(Delegate)
这是iOS开发中最经典的解耦方式之一,类型安全且逻辑清晰,非常适合父子控制器的场景:
// 首先定义一个代理协议 protocol ChildViewControllerDelegate: AnyObject { func childViewControllerDidDisappear(_ childVC: ChildViewController) } // 子控制器中声明代理属性(注意用weak避免循环引用) class ChildViewController: UIViewController { weak var delegate: ChildViewControllerDelegate? override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // 当视图消失时,通知代理 delegate?.childViewControllerDidDisappear(self) } } // 父控制器遵守协议并实现代理方法 class ParentViewController: UIViewController, ChildViewControllerDelegate { func showChildVC() { let childVC = ChildViewController() childVC.delegate = self present(childVC, animated: true) } // 实现代理方法,在这里处理子控制器消失后的逻辑 func childViewControllerDidDisappear(_ childVC: ChildViewController) { print("子控制器已经消失,父控制器执行自定义操作") // 比如刷新父页面数据、更新UI等 } }
这种方式的好处是耦合度低,父控制器和子控制器通过协议交互,换不同的父控制器只要遵守协议实现方法就行,不用修改子控制器的代码。
方案2:闭包(Closure)
如果场景比较简单,闭包是更轻便的选择,写法更简洁:
// 子控制器中定义一个闭包属性 class ChildViewController: UIViewController { var onViewDisappear: (() -> Void)? override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // 触发闭包 onViewDisappear?() } } // 父控制器中设置闭包回调 class ParentViewController: UIViewController { func showChildVC() { let childVC = ChildViewController() // 注意用[weak self]避免循环引用 childVC.onViewDisappear = { [weak self] in guard let self = self else { return } self.handleChildDisappear() } present(childVC, animated: true) } private func handleChildDisappear() { print("子控制器消失,父控制器执行操作") } }
闭包的优势是代码更紧凑,不需要额外定义协议,适合一次性的回调场景,但要注意管理好引用关系,避免内存泄漏。
方案3:通知中心(NotificationCenter)
如果你的场景需要跨多个组件或者不需要直接持有子控制器的引用,可以用通知中心,但要记得及时移除通知:
// 先定义一个专属的通知名称 extension Notification.Name { static let childVCDidDisappear = Notification.Name("ChildViewControllerDidDisappear") } // 子控制器中发送通知 class ChildViewController: UIViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // 发送通知,还可以携带object或者userInfo传递额外信息 NotificationCenter.default.post(name: .childVCDidDisappear, object: self) } } // 父控制器中监听通知 class ParentViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 添加通知监听 NotificationCenter.default.addObserver( self, selector: #selector(handleChildDisappear(_:)), name: .childVCDidDisappear, object: nil ) } deinit { // 一定要在销毁时移除通知,避免野指针 NotificationCenter.default.removeObserver(self) } @objc private func handleChildDisappear(_ notification: Notification) { // 可以拿到发送通知的子控制器实例 if let childVC = notification.object as? ChildViewController { print("子控制器\(childVC)已经消失") } // 执行父控制器的逻辑 } }
通知中心的耦合性最低,但缺点是不够类型安全,而且需要手动管理通知的注册和移除,一般适合复杂的跨模块场景。
总结
如果是父子控制器这种明确的依赖关系,优先选择代理模式或者闭包,它们类型安全、逻辑清晰;如果是跨多个无关组件的场景,再考虑用通知中心。
内容的提问来源于stack exchange,提问作者Entretoize
相关产品推荐
相关产品推荐

