Reputation: 1295
I've come across an issue where I cannot access my app's main window, as it returns nil.
let window = NSApplication.sharedApplication().mainWindow
I've found similar questions:
How to get Main Window (App Delegate) from other class (subclass of NSViewController)?
But doing:
let window = (NSApplication.sharedApplication() as! NSArray).objectAtIndex(0)
Doesn't seem to work either.
Do I have to mess around in Storyboard?
Thanks in advance.
Update:
I'm actually trying to port something from Objective-C.
NSWindow *mainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
NSLog(@"%@", mainWindow.contentViewController);
This returns a proper value, when put in the viewDidLoad()
block in a NSViewController
, so I'm guessing there is something wrong with NSApplication.sharedApplication()
.
Upvotes: 12
Views: 4269
Reputation: 5183
For me the accepted answer did not work. The documentation for activate(ignoringOtherApps:)
says:
...you shouldn’t assume the app will be active immediately after sending this message.
For this reason, mainWindow
will most likely remain nil
. So for me the following works:
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)
}
}
Usage:
NSApplication.withKeyOrMainWindow { window in
alert.beginSheetModal(for: window) { (response: NSApplication.ModalResponse) in
handler?(response)
}
}
Upvotes: 0
Reputation: 9121
If your app only contains one window, or always starts with the same window without even removing it from memory, you can use this code:
if let window = NSApp.windows.first {
window.makeKeyAndOrderFront(self) // Or do something else
}
If you need the window during startup of your app, you should load this code async, like this:
DispatchQueue.main.async {
if let window = NSApp.windows.first {
window.makeKeyAndOrderFront(self)
}
}
Upvotes: 1
Reputation: 2675
Make sure you have a Window in your storyboard as Initial Controller
Upvotes: 0
Reputation: 9848
It also can return nil if the main app window is not active on macOS. For instance I ran into this when I was making a drag and drop file uploader. If the window was not in the front (on the operating system) it would return nil. The following line of code will activate your app (bring to front)
NSApp.activateIgnoringOtherApps(true)
I also needed a timer to delay my call of mainWindow in my case.
Upvotes: 9
Reputation: 333
You could do this instead:
func applicationDidBecomeActive(notification: NSNotification) {
NSApplication.sharedApplication().mainWindow?.movable = false
}
Upvotes: 3
Reputation: 90521
From 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 benil
when the app is inactive or hidden.
So, this is a perfectly normal thing to have happen, depending on the circumstances.
Upvotes: 1