监听NSStatusItem的isVisible属性时KVO回调触发两次问题求助
这个重复回调是macOS AppKit框架中NSStatusItem的KVO实现存在的已知问题,isVisible属性的变更通知会被底层重复发送,两次通知的参数完全一致,无法通过change对象的内置字段直接区分。
根据你的需求,有两种成熟的解决方案:
方案1:添加防抖逻辑过滤重复回调
如果需要监听所有场景下的isVisible属性变更,可以用主队列延时防抖过滤重复事件,两次回调默认在同一个RunLoop周期内触发,设置100ms的延时足够过滤重复,且不会对用户体验产生可感知的影响:
// 全局声明防抖任务容器 private var observeWorkItem: DispatchWorkItem? // 原有KVO监听逻辑修改如下 observer = statusItem.observe(\.isVisible, options: [.old, .new]) { [weak self] object, change in guard let oldValue = change.oldValue, let newValue = change.newValue else { return } // 取消上一次未执行的待处理任务 self?.observeWorkItem?.cancel() // 创建新的业务处理任务 let workItem = DispatchWorkItem { // 此处替换为你的实际业务逻辑 print("oldValue: \(oldValue) newValue: \(newValue)") } self?.observeWorkItem = workItem DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: workItem) }
方案2:使用系统移除通知替代KVO
如果你仅需要检测用户拖拽移除状态项的场景,直接监听系统提供的NSStatusItemDidRemoveNotification更合适,该通知只会触发一次,不需要处理重复事件:
NotificationCenter.default.addObserver( forName: NSStatusItem.didRemoveNotification, object: statusItem, queue: .main ) { _ in // 此处替换为状态项被移除后的业务逻辑 print("状态项已被用户拖拽移除") }
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

