NSEvent泄漏导致macOS中的密钥丢失

时间:2019-03-11 14:52:21

标签: swift macos cocoa nsevent

在带有Swift 4.2的Xcode 10.1中,当在我的NSViewController中添加用于按键事件的本地监视器时,发生了内存泄漏,它被实例化为最小版本(没有nib和xib)。

override func loadView() {
    self.view = NSView()
    self.view.wantsLayer = true
}

override func viewDidLoad(){
    super.viewDidLoad
    NSEvent.addLocalMonitorForEvents(matching: .keyDown, handler: handler)
}

lazy var handler:(NSEvent)->NSEvent? = { [ weak self ,unowned picker = picker] event in
    picker.keyDown(with: event)
    return event
}

此内存泄漏没有太多信息:Memory leak

编辑

在deinit方法中,调用removeMonitor

deinit {
   NSEvent.removeMonitor(self)
}

编辑2

问题已解决:

    override func loadView() {
    self.view = NSView()
    self.view.wantsLayer = true
}
var monitor:Any? // This is essential

override func viewDidLoad(){
    super.viewDidLoad
    monitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown, handler: handler)
}

lazy var handler:(NSEvent)->NSEvent? = { [ weak self ,unowned picker = picker] event in
    picker.keyDown(with: event)
    return event
}

deinit {
   NSEvent.removeMonitor(monitor)
}

1 个答案:

答案 0 :(得分:0)

来自Apple Docs

  

注意

     

所有与掩码匹配的将来事件都将调用监视器Block。您必须致电removeMonitor(_:)来停止监视器。在垃圾回收下,只有调用removeMonitor(_:)才会收集监视器(以及块引用的所有内容)。

意味着监视器将继续寻找匹配的事件,直到调用removeMonitor()。因此,您的系统正在使用额外的内存来继续查找事件,并且如果您从未调用过此方法,则可能导致相当大的内存泄漏。就像它说的那样,即使使用垃圾回收,该对象仍然被分配-因为它正在寻找随时可能发生的事件(因此不能保证将其收集)。当您希望系统停止查找事件时,请确保调用此函数。

您还可以在handler中进行类似的操作。

  

您可以返回未修改的事件,创建并返回新的NSEvent对象,或者返回nil以停止事件的分派。