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

无需子类化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:33:54