使用 Cocoa 在 Objective-C 的事件处理程序中删除本地事件监视器的竞争条件

Race condition removing local event monitor in event handler in Objective-C using Cocoa

我正在使用 Cocoa 框架在 Objective-C 中创建本地事件监视器,想知道这是否会引入竞争条件:

id monitor = [NSEvent addLocalMonitorForEventsMatchingMask:
    (NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown)
    handler:^(NSEvent* event)
    {
        [NSEvent removeMonitor:monitor];
    }];

您的代码无法编译,因为该块没有 return 值,所以您可能为了发布而简化了太多。

接下来,块中 monitor 的值将始终是 nil,因为它的值是作为块构造的一部分复制的 before addLocalMonitorForEventsMatchingMask returns 并将值分配给 monitor.

您可以通过将 monitor 声明为 __block 来解决最后一个问题,从而捕获变量而不是它的值,但是这会让您:

你有一个参考循环。由 addLocalMonitorForEventsMatchingMask 编辑的不透明监视器对象 return 在其中包含对您的块的引用,并且您的块包含对监视器对象的引用。这不会影响监控的操作或删除,它只是意味着永远不会收集监控对象和块对象。您可以在执行 removeMonitor.

时通过在块中 niling monitor 来解决此问题

这让我们想到了您的最后一个问题,是否存在竞争条件?大概你的意思是在事件系统为一个事件调用你的监视器和试图在下一个事件中调用它之间。我不知道我们是否可以肯定地说,但是 removeMonitor 的文档没有提到要采取的任何预防措施,并且初始事件处理是通过 "queue" 完成的,表明系统不会开始处理跟踪事件,直到它至少将当前事件发送到您的应用程序。这确实强烈表明竞争条件在这里不是问题。

但是请注意,文档,甚至 Swift 版本,都使用了术语 "garbage collection",尽管 ARC 是一种 GC,Apple 倾向于保留长期弃用的术语 pre-ARC(和 pre-Swift)垃圾收集器 - 表明文档没有被修改(在计算机术语中)。也许其他人会对此提供明确的答案。

HTH