无需子类化ViewController,实现VC1监听VC2 dismissal通知
不用子类化VC2,让VC1接收其dismiss通知的方案
当然有办法!不用子类化VC2也能轻松追踪它的dismiss事件,给你几个实用的方案,按需选择:
方案1:利用present方法的completion闭包(最推荐)
这是最简单直接的方式,完全不需要修改VC2的任何代码,所有逻辑都在VC1里处理。当你在VC1中present VC2时,直接传入一个completion闭包,这个闭包会在VC2被dismiss完成后自动执行:
// 在VC1的代码中 let vc2 = VC2() present(vc2, animated: true) { // VC2被dismiss后会执行这里的代码 print("VC2已经被dismiss了") // 在这里处理VC1需要更新的逻辑,比如刷新列表、重置UI状态等 }
这个方案适合单次监听的场景——也就是你只关心当前这个VC2实例的dismiss事件,不需要全局监听所有VC2的实例。
方案2:用KVO监听VC2的状态变化
如果你需要在VC2开始被dismiss时就收到通知(而不是等dismiss完成),或者需要更灵活的状态追踪,可以使用KVO(键值观察)监听VC2的isBeingDismissed属性:
// 在VC1中定义一个KVO观察对象的引用,避免被提前释放 var dismissObservation: NSKeyValueObservation? // present VC2时设置监听 let vc2 = VC2() dismissObservation = vc2.observe(\.isBeingDismissed, options: [.new]) { [weak self] _, change in guard let isBeingDismissed = change.newValue, isBeingDismissed else { return } // VC2正在被dismiss,这里可以执行前置逻辑 print("VC2开始被dismiss") // 如果需要等dismiss完成,可以结合viewDidDisappear或者延迟执行 DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { print("VC2 dismiss动画完成") self?.updateUIAfterVC2Dismiss() } } present(vc2, animated: true)
注意事项:
- 一定要用
[weak self]避免循环引用 - 在VC1的
deinit方法中记得将dismissObservation置为nil,释放监听
方案3:Method Swizzling(慎用,适合全局监听)
如果你的App中需要监听所有VC2实例的dismiss事件,而且不想子类化,可以用Method Swizzling(方法交换)来hook VC2的dismiss方法,在它被调用时发送通知。不过这属于“黑魔法”,使用时要谨慎,避免和其他代码冲突:
首先,给VC2写一个扩展来实现方法交换:
extension VC2 { static func swizzleDismissMethod() { let originalSelector = #selector(dismiss(animated:completion:)) let swizzledSelector = #selector(swizzledDismiss(animated:completion:)) guard let originalMethod = class_getInstanceMethod(self, originalSelector), let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else { return } // 交换方法实现 method_exchangeImplementations(originalMethod, swizzledMethod) } @objc private func swizzledDismiss(animated: Bool, completion: (() -> Void)?) { // 先执行原有的dismiss逻辑 self.swizzledDismiss(animated: animated, completion: { // 先执行原本的completion completion?() // 发送通知告诉VC1(或其他监听者)VC2被dismiss了 NotificationCenter.default.post(name: NSNotification.Name("VC2DidDismissNotification"), object: nil) }) } }
然后在VC1中注册监听:
// 在VC1的viewDidLoad或初始化方法中 override func viewDidLoad() { super.viewDidLoad() // 只需要调用一次方法交换,建议在App启动时执行,而不是每个VC1都调用 VC2.swizzleDismissMethod() // 注册通知监听 NotificationCenter.default.addObserver(self, selector: #selector(handleVC2Dismiss), name: NSNotification.Name("VC2DidDismissNotification"), object: nil) } @objc private func handleVC2Dismiss() { print("收到VC2被dismiss的通知") // 处理逻辑 } // 记得在VC1销毁时移除监听 deinit { NotificationCenter.default.removeObserver(self) }
注意事项:
- 方法交换只需要执行一次,建议在
AppDelegate的didFinishLaunchingWithOptions中调用,避免重复交换 - 如果你用了第三方库,要注意避免方法名冲突
- 这种方式会影响所有VC2的实例,所以要确保你的逻辑是全局适用的
内容的提问来源于stack exchange,提问作者topgun
相关产品推荐
相关产品推荐

