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

Combine与NotificationCenter结合时通知无法接收的问题求助

问题分析与解决方案

这个问题我之前踩过坑!核心原因是你没有持有Combine订阅返回的AnyCancellable对象——一旦代码执行完当前作用域,这些订阅实例就会被立即销毁,自然收不到后续的通知。而旧版的addObserver方式是把观察者注册到NotificationCenter,只要self还存活就能正常收到通知,所以不受影响。

为什么Playground里能正常运行?

Playground的执行环境比较特殊,临时创建的对象生命周期会被自动延长,那些没被持有的AnyCancellable不会马上被释放,所以能收到通知。但在真实iOS项目中,作用域结束后这些对象就会被ARC回收,订阅也就随之取消了。

修复代码示例

只需要在你的类中添加一个属性来存储订阅对象即可,推荐用Set<AnyCancellable>来管理多个订阅:

// 假设你的代码在一个ViewController或自定义类中
class YourTestClass: UIViewController {
    // 用Set来持有所有Combine订阅,自动管理生命周期
    private var cancellables = Set<AnyCancellable>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // SOLUTION 1 修正:添加store(in:)持有订阅
        NotificationCenter.default
            .publisher(for: .Test)
            .sink(receiveCompletion: { _ in
                print("SOLUTION 1: COMPLETION")
            }, receiveValue: { _ in
                print("SOLUTION 1: VALUE")
            })
            .store(in: &cancellables)
        
        // SOLUTION 2 修正:同样添加store(in:)
        NotificationCenter.Publisher(center: .default, name: .Test)
            .sink(receiveCompletion: { _ in
                print("SOLUTION 2: COMPLETION")
            }, receiveValue: { _ in
                print("SOLUTION 2: VALUE")
            })
            .store(in: &cancellables)
        
        // SOLUTION 3 保持不变
        NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: .Test, object: nil)
        
        // 发送通知测试
        NotificationCenter.default.post(name: .Test, object: nil)
        NotificationCenter.default.post(name: .Test, object: nil)
    }
    
    @objc func doSomething() {
        print("SOLUTION 3: VALUE")
    }
}

extension Notification.Name {
    static let Test = Notification.Name(rawValue: "Test")
}

额外小提示

如果只需要管理单个订阅,也可以用单独的AnyCancellable?属性存储:

private var testNotificationCancellable: AnyCancellable?

// 赋值方式
testNotificationCancellable = NotificationCenter.default
    .publisher(for: .Test)
    .sink(...)

用Set的优势是可以统一管理多个订阅,后续不需要的订阅也可以通过cancel()方法从Set中移除,非常方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:04:08