Как правильно закрыть поповер?
В моем подклассе NSDocument я создаю экземпляр NSPopover, с .semitransient
поведение, и показать это:
popover.show(relativeTo: rect, of: sender, preferredEdge: .maxX)
popover
объявлен локально. Метод кнопки в контроллере поповера вызывает:
view.window?.close()
Поповер закрывается, но я осознал, что он остается в памяти, deinit()
никогда не вызывается и NSApp.windows
количество увеличивается, тогда как если я отклоняю его, нажимая escape или щелкая снаружи, deinit
вызывается и количество окон не увеличивается.
Если я установлю окно .isReleasedWhenClosed
в true
количество окон не увеличивается, но deinit по-прежнему не вызывается.
(Swift 3, Xcode 8)
3 ответа
Вы должны вызвать executeClose (или закрыть) для всплывающего окна, а не окна.
Спасибо -DrummerB за ваш интерес. Мне потребовалось некоторое время, чтобы приступить к созданию простого тестового приложения, которое я мог бы отправить вам, и, конечно, оно не было основанным на документах, как у меня, и, похоже, это затуманило проблему. Мой способ открыть поповер был основан на примере, который я недавно прочитал, но сейчас не могу найти или предупредить людей. Это пошло так:
let popover = NSPopover
let controller = MyPopover(...)! // my convenience init for NSViewController descendant
popover.controller = controller
popover.behaviour = .semitransient // and setting other properties
popover.show(relativeTo: rect, of: sender, preferredEdge: .maxX)
Вот улучшенный способ, с которым я столкнулся:
let controller = MyPopover(...)! // descendant of NSViewController
controller.presentViewController(controller,
asPopoverRelativeTo: rect, of: sender, preferredEdge: .maxX,
behavior: .semitransient) // sender was a NSTable
В контроллере вида действие кнопки "Готово" просто выполняет:
dismissViewController(self)
который никогда не работал раньше. И теперь я нахожу, что список окон приложения не растет, а контроллер deinit
бывает надежно.
Я бы предложил сделать следующее:
Определите такой протокол
protocol PopoverManager {
func dismissPopover(_ sender: Any)
}
В вашем popoverViewController (в этом примере мы отображаем контроллер представления фильтра как всплывающее окно) добавьте переменную для popoverManager, как это
/// Filter shown as a NSPopover()
class FilterViewController: NSViewController {
// Delegate
var popoverManager: PopoverManager?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
// Bind this to the close button or action on your popover view controller
@IBAction func closeAction(_ sender: Any) {
self.popoverManager?.dismissPopover(sender)
}
...
}
Теперь в вашем viewController вы показываете всплывающее окно, добавляя расширение, подобное этому.
extension MainViewController: NSPopoverDelegate, PopoverManager {
@IBAction func setFilter(_ sender: AnyObject) {
self.showFilterPopover(sender)
}
func showFilterPopover(_ sender: AnyObject) {
let storyboard = NSStoryboard(name: "Filter", bundle: nil)
guard let controller = storyboard.instantiateController(withIdentifier: "FilterViewController") as? FilterViewController else {
return
}
// Set the delegate to self so we can dismiss the popover from the popover view controller itself.
controller.popoverManager = self
self.popover = NSPopover()
self.popover.delegate = self
self.popover.contentViewController = controller
self.popover.contentSize = controller.view.frame.size
self.popover.behavior = .applicationDefined
self.popover.animates = true
self.popover.show(relativeTo: sender.bounds, of: sender as! NSView, preferredEdge: NSRectEdge.maxY)
}
func dismissPopover(_ sender: Any) {
self.popover?.performClose(sender)
// If you don't want to reuse it
self.popover = nil
}
}