NSEvent утечка для ключа вниз в macOS - PullRequest
0 голосов
/ 11 марта 2019

В Xcode 10.1 с Swift 4.2 у меня возникает утечка памяти, когда я добавляю локальный монитор для событий нажатия клавиш в моем 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
}

Эта утечка памяти содержит мало информации: Утечка памяти

РЕДАКТИРОВАТЬ

В методе 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 Ответ

1 голос
/ 11 марта 2019

Из Apple Docs ;

Примечание

Монитор Block вызывается для всех будущих событий, соответствующих маске.Вы должны позвонить removeMonitor(_:), чтобы остановить монитор.При сборке мусора монитор (и все ссылки на блоки) не будет собираться до тех пор, пока не будет вызван removeMonitor(_:).

Это означает, что монитор будет продолжать поиск совпадающих событий, пока не будет вызван removeMonitor(),Таким образом, ваша система использует дополнительную память для поиска событий, и если вы никогда не вызовете это - это может привести к довольно большой утечке памяти.Как говорится даже при сборке мусора, этот объект все еще выделяется - потому что он ищет события, которые могут произойти в любое время (поэтому не гарантируется, что он будет собран).Обязательно звоните, когда хотите, чтобы система перестала искать события.

Вы также можете сделать что-то подобное в вашем handler.

Вы можете вернуть событие неизмененным, создать и вернуть новый объект NSEvent или вернуть nil, чтобы остановить диспетчеризациюсобытия.

...