在我的NSDocument子类中,我实例化一个具有.semitransient
行为的NSPopover,并显示它:
popover.show(relativeTo: rect, of: sender, preferredEdge: .maxX)
popover
在本地声明。弹出控制器中的按钮方法调用:
view.window?.close()
popover关闭,但我已经意识到它仍在内存中,deinit()
从未被调用且NSApp.windows
计数增加,而如果我通过按下escape或点击它来解除它,{ {1}} 被调用,并且窗口计数不会增加。
如果我将窗口的deinit
设置为.isReleasedWhenClosed
,则窗口计数不会增加,但仍然不会调用deinit。
(Swift 3,Xcode 8)
答案 0 :(得分:0)
你必须在弹出窗口而不是窗口上调用performClose(或close)。
答案 1 :(得分:0)
感谢-DrummerB感兴趣。我花了一些时间来制作一个我可能发送给你的简单测试应用程序,当然它不像我的那样是一个基于文档的应用程序,这似乎使问题蒙上阴影。我打开popover的方式基于我最近阅读的一个例子,但现在无法找到或者我警告人们。它是这样的:
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
可靠地发生。
答案 2 :(得分:0)
我建议您执行以下操作:
定义一个这样的协议
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
}
}