使用自定义NSApplication创建时,NSWindow不会关闭

时间:2016-07-07 18:00:56

标签: swift cocoa nswindow

我正在创建自己的NSApplication子类,并且遇到了障碍。这是我对run()方法的实现。

override func run() {
    finishLaunching()
    repeat {

        let event = nextEventMatchingMask(0xfffffffffffffff, untilDate: NSDate.distantPast(), inMode: NSDefaultRunLoopMode, dequeue: true)
        if event != nil { sendEvent(event!) }
        updateWindows()

    } while true

}

在我的main.swift我有这个:

let myApp: MyApplication = MyApplication.sharedApplication() as! MyApplication

let window = NSWindow(contentRect: NSMakeRect(0, 0, 100, 100), styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask , backing: .Buffered, defer: false)
window.makeKeyAndOrderFront(nil)

myApp.run()

0xfffffffffffffff而不是Int(NSEventMask.AnyEventMask.rawValue)的原因是因为后者在从UInt64转换为Int时溢出。

问题是,当我点击红色关闭按钮时,窗口没有关闭,当我选择"退出"从停靠图标菜单,它不会退出。为什么会这样?

编辑:this answer.

中讨论了同样的问题

编辑2:我已经创建了此代码的Objective-c版本,一切正常。我怀疑问题是我无法在Swift中使用NSAnyEventMask。

2 个答案:

答案 0 :(得分:1)

您应该只在self.running时重复。这可以解释为什么您的应用程序不会退出。如果您的应用配置为在最后一个窗口关闭时退出,它也可以解释为什么您的窗口不会关闭。无论如何,如果整个应用程序要退出,框架可能不会单独关闭窗口。

答案 1 :(得分:0)

我似乎已经解决了这个问题,在Objective-C中我可以使用它,我的应用程序将响应停靠菜单中的退出项目。

NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask 
                                    untilDate:nil 
                                       inMode:NSDefaultRunLoopMode 
                                      dequeue:YES];

如果你想尝试下一个类似的事件,那么在Swift中你会这样做:

let event = nextEventMatchingMask(Int(NSEventMask.AnyEventMask.rawValue),
                                  untilDate: NSDate.distantPast(), 
                                  inMode: NSDefaultRunLoopMode, 
                                  dequeue: true)

但是,从UInt64转换为Int时会出现溢出错误。这似乎是无意的。首先,我尝试将其替换为0xfffffffffffffff来解决此问题。这工作正常,应用程序将响应事件。但实际上这还不够。该应用还需要响应与掩码0x1匹配的事件。我不明白为什么,但这允许我从Dock菜单中退出并隐藏我的应用程序。 (0x0只允许我退出。)

那么,Swift NSApplication子类的整个run()实现是这样的:

override func run() {
    finishLaunching()
    setValue(true, forKey: "running")

    while true {
        let event = nextEventMatchingMask(0xfffffffffffffff, untilDate: NSDate.distantPast(), inMode: NSDefaultRunLoopMode, dequeue: true)
        let dockEvent = nextEventMatchingMask(0x1, untilDate: NSDate.distantPast(), inMode: NSDefaultRunLoopMode, dequeue: true)

        if dockEvent != nil { sendEvent(dockEvent!) }
        if event != nil { sendEvent(event!) }

        if !running { break }

        updateWindows()
    }
}