#swift #macos #cocoa #nsevent
#swift #macos #cocoa #nsevent
Вопрос:
В Xcode 10.1 с Swift 4.2 у меня возникает утечка памяти, когда я добавляю локальный монитор для событий отключения ключа в мой NSViewController, чтобы он был создан как минимальная версия (без наконечника и 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. Вы удаляете монитор событий, когда контроллер просмотра отключен?
2. Включите код из изображения в виде текста.
3. Добавьте localmonitorforevents Обратите внимание, что Блок монитора вызывается для всех будущих событий, которые соответствуют mask. Вы должны вызвать removeMonitor: чтобы остановить монитор. При сборке мусора монитор (и все, на что ссылается блок) не будет собран до тех пор, пока не будет вызван removeMonitor: .
4. Я удаляю его методом deinit с помощью NSEvent.removeMonitor (self). Это верно?. Утечки сохраняются
Ответ №1:
Из документов Apple;
Примечание
Монитор
Block
вызывается для всех будущих событий, которые соответствуют маске. Вы должны вызватьremoveMonitor(_:)
, чтобы остановить монитор. При сборке мусора монитор (и все, на что ссылается блок) не будут собраны доremoveMonitor(_:)
вызова.
Это означает, что монитор будет продолжать искать совпадающие события до тех пор, пока не будет вызван removeMonitor()
. Итак, ваша система использует дополнительную память для продолжения поиска событий, и если вы никогда не вызовете это — это может привести к довольно большой утечке памяти. Как говорится, даже при сборке мусора этот объект все еще выделяется — потому что он ищет события, которые могут произойти в любое время (поэтому не гарантируется, что это будет собрано). Убедитесь, что вы вызываете это, когда хотите, чтобы система прекратила поиск событий.
Вы также могли бы сделать что-то подобное в своем handler
.
Вы можете вернуть событие без изменений, создать и вернуть новый объект NSEvent или вернуть nil, чтобы остановить отправку события.
Комментарии:
1. Я удаляю его методом deinit с помощью NSEvent.removeMonitor (self). Это верно?. Утечки сохраняются
2. Правильно, вы должны передать монитор, который хотите удалить, не самостоятельно.
self
— это ваш класс, который содержит монитор. Это ничего не даст.