NSWindow returns 无 (NSApplication)

NSWindow returns nil (NSApplication)

我遇到了一个问题,我无法访问我的应用程序的主 window, 因为它 returns nil.

let window = NSApplication.sharedApplication().mainWindow

我发现了类似的问题:

How to get Main Window (App Delegate) from other class (subclass of NSViewController)?

但是正在做:

let window = (NSApplication.sharedApplication() as! NSArray).objectAtIndex(0)

好像也不行。

我必须在 Storyboard 中乱搞吗?

提前致谢。

更新:

我实际上是在尝试从 Objective-C 移植一些东西。

    NSWindow *mainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
    NSLog(@"%@", mainWindow.contentViewController);

这个 returns 是一个正确的值,当放在 NSViewControllerviewDidLoad() 块中时,所以我猜 NSApplication.sharedApplication() 有问题。

来自the docs

The value in this property is nil when the app’s storyboard or nib file has not yet finished loading. It might also be nil when the app is inactive or hidden.

因此,发生这种情况是完全正常的,具体取决于具体情况。

您可以这样做:

   func applicationDidBecomeActive(notification: NSNotification) {

        NSApplication.sharedApplication().mainWindow?.movable = false
    }

如果主应用 window 在 macOS 上未激活,它也可以 return nil。例如,当我制作拖放文件上传器时,我 运行 进入了这个。如果 window 不在前面(在操作系统上),它将 return 为零。以下代码行将激活您的应用程序(置于最前面)

NSApp.activateIgnoringOtherApps(true)

在我的例子中,我还需要一个计时器来延迟调用 mainWindow。

确保你的故事板中有一个 Window 作为 Initial Controller

如果您的应用仅包含一个 window,或者始终以相同的 window 开头,甚至没有将其从内存中删除,您可以使用此代码:

if let window = NSApp.windows.first {
    window.makeKeyAndOrderFront(self) // Or do something else
}

如果您在应用程序启动期间需要 window,您应该异步加载此代码,如下所示:

DispatchQueue.main.async {
    if let window = NSApp.windows.first {
        window.makeKeyAndOrderFront(self)
    }
}

对我来说,接受的答案没有用。 activate(ignoringOtherApps:) 的文档说:

...you shouldn’t assume the app will be active immediately after sending this message.

因此,mainWindow 很可能会保持 nil。所以对我来说,以下作品:

extension NSApplication {
  /// Activates the app so main window / key window are no longer `nil`. Pauses a bit between activations and keeps trying.
  /// - Parameter completion: completion called with the key / main window
  @objc public static func withKeyOrMainWindow(mainOnly: Bool = false, completion: @escaping (_ window: NSWindow)->Void) {
    DispatchQueue.main.async {
      let window = mainOnly ? NSApplication.shared.mainWindow : NSApplication.shared.keyWindow ?? NSApplication.shared.mainWindow
      if let window = window {
        completion(window)
      }
      else {
        // Activate the app
        NSApp.activate(ignoringOtherApps: true)
        
        // Short delay
        DispatchQueue.main.asyncAfter(deadline: .now()+0.2) {
          NSApplication.withKeyOrMainWindow(completion: completion)
        }
      }
    }
  }
  
  /// Activates the app so main window is no longer `nil`. Pauses a bit between activations and keeps trying.
  /// - Parameter completion: completion called with the main window
  @objc public static func withMainWindow(completion: @escaping (_ window: NSWindow)->Void) {
    return withKeyOrMainWindow(mainOnly: true, completion: completion)
  }
}

用法:

NSApplication.withKeyOrMainWindow { window in
  alert.beginSheetModal(for: window) { (response: NSApplication.ModalResponse) in
        handler?(response)
  }
}