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

Swift中从另一个ViewController移除通知观察者的问题

解决VCA通知观察者重复注册及跨VC移除的问题

首先得指出你之前尝试的问题所在:在VCB里调用instantiateViewController(withIdentifier:)得到的是全新的VCA实例,根本不是当前后台运行的那个VCA对象,所以移除操作完全没作用在正确的目标上,这就是为什么你的代码无效。

下面给你几个可行的解决方案,按推荐程度排序:

方案一:用闭包回调替代通知(最推荐)

这种一对一的VC间通信,闭包比通知更简洁,还能彻底避免观察者管理的麻烦:

  1. 在VCB里定义一个闭包属性:
class VCB: UIViewController {
    // 定义回调闭包,点击按钮时触发
    var onTriggerAction: (() -> Void)?
    
    @IBAction func buttonPressed(_ sender: Any) {
        // 直接调用闭包触发VCA的方法
        onTriggerAction?()
    }
    
    @IBAction func backButtonPressed(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
}
  1. 在VCA跳转VCB时,绑定闭包逻辑:
// VCA中present VCB的代码示例
let vcb = storyboard?.instantiateViewController(withIdentifier: "VCB") as! VCB
// 用weak self避免循环引用
vcb.onTriggerAction = { [weak self] in
    self?.someFunction()
}
present(vcb, animated: true)

这样完全不需要处理通知观察者,逻辑清晰还不容易出错。

方案二:修正通知观察者的移除逻辑(如果坚持用通知)

第一步:获取正确的VCA实例

因为VCB是被VCA present出来的,所以VCB的presentingViewController就是你要操作的那个VCA实例,直接强转后操作即可:

@IBAction func backButtonPressed(_ sender: Any) {
    // 拿到当前后台的VCA实例
    if let targetVCA = self.presentingViewController as? VCA {
        NotificationCenter.default.removeObserver(targetVCA, name: Notification.Name("name"), object: nil)
    }
    dismiss(animated: true, completion: nil)
}

第二步:避免重复注册观察者

即使解决了移除问题,每次viewDidAppear都添加观察者还是会导致重复注册,建议在添加前先移除一次:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 先移除再添加,确保同一时刻只有一个观察者
    NotificationCenter.default.removeObserver(self, name: Notification.Name("name"), object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(someFunction), name: Notification.Name("name"), object: nil)
}

进阶优化:用Block式观察者(iOS 9+)

Block式观察者会返回一个token,能更精准地管理,还能避免Selector的写法:

class VCA: UIViewController {
    // 保存观察者token
    private var notificationToken: NSObjectProtocol?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 先移除旧的观察者
        if let token = notificationToken {
            NotificationCenter.default.removeObserver(token)
        }
        // 添加Block式观察者
        notificationToken = NotificationCenter.default.addObserver(forName: Notification.Name("name"), object: nil, queue: .main) { [weak self] _ in
            self?.someFunction()
        }
    }
    
    // 提供外部调用的移除方法
    func cleanUpNotificationObserver() {
        if let token = notificationToken {
            NotificationCenter.default.removeObserver(token)
            notificationToken = nil
        }
    }
}

然后在VCB的返回按钮方法里调用这个方法:

@IBAction func backButtonPressed(_ sender: Any) {
    if let targetVCA = self.presentingViewController as? VCA {
        targetVCA.cleanUpNotificationObserver()
    }
    dismiss(animated: true, completion: nil)
}

内容的提问来源于stack exchange,提问作者kasperonline

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:03:45