You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:15:13