在带有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)
}
答案 0 :(得分:0)
来自Apple Docs;
注意
所有与掩码匹配的将来事件都将调用监视器
Block
。您必须致电removeMonitor(_:)
来停止监视器。在垃圾回收下,只有调用removeMonitor(_:)
才会收集监视器(以及块引用的所有内容)。
意味着监视器将继续寻找匹配的事件,直到调用removeMonitor()
。因此,您的系统正在使用额外的内存来继续查找事件,并且如果您从未调用过此方法,则可能导致相当大的内存泄漏。就像它说的那样,即使使用垃圾回收,该对象仍然被分配-因为它正在寻找随时可能发生的事件(因此不能保证将其收集)。当您希望系统停止查找事件时,请确保调用此函数。
您还可以在handler
中进行类似的操作。
您可以返回未修改的事件,创建并返回新的NSEvent对象,或者返回nil以停止事件的分派。