The default behaviour of XCode Cocoa Mac OS app is that when the window close button is it, it simply closes the app window. However the App doesn’t quit.
Which means that the app is still running and when we try launching it again, nothing will happen. We have to manually quit the app (e.g. by right clicking the app icon in dock and clicking quit) to close it properly.
In this tutorial we will learn how to make xcode swift cocoa app quit on windows close event, making swift terminate application when window closes instead of just hiding the active window.
How to quit cocoa app when window close using swift
This code is tested on xcode 8.2 with swift 3.0.1 on macbook pro running MacOS Sierra 10.12.2.
Handing it needs three steps:
- Conform toNSWindowDelegate in your ViewController class
- Override viewDidAppear method
- Add windowShouldClose method
Lets see them in detail.
1. Conform toNSWindowDelegate in your ViewController class
First step is to make ourViewController class conform to the NSWindowDelegate. To do this, simply add NSWindowDelegate to the class declaration like this:
class ViewController: NSViewController, NSWindowDelegate { // ... rest of the code goes here
Yes we can add as many protocols that we want to, separated by commas, just for info if you didn’t know already.
2. Override viewDidAppear method
We need to override the default viewDidAppear method and add our code to it. It should look like this:
override func viewDidAppear() { self.view.window?.delegate = self }
Why aren’t we using viewDidLoad instead of viewDidAppear? Because self.view.window isn’t defined in viewDidLoad probably in some situations (or all?).
3. Add windowShouldClose method
This method will be called when the window is about to be closed. First lets see the swift code then discuss it. We simply need to add this code:
func windowShouldClose(_ sender: Any) { NSApplication.shared().terminate(self) }
Note:
Xcode might give you a warning (not an error) at this point, however ignore this error and don’t do any of the suggested changes by xode or our code won’t work. Which means:
- Don’t make the method private.
- Don’t add @nonobjc to the method declaration.
Also note that (_sender: Any) is required otherwise it wont work.
Return isn’t required as the application is going to terminate anyway. However if you do add the return, do it like this and then possibly return something too. (I would suggest to simply leave the return part unless you know what you’re doing)
func windowShouldClose(_ sender: Any) -> Bool { NSApplication.shared().terminate(self) return true }
Also, we can replace NSApplication.shared().terminate(self) with exit(0) too, however I don’t recommend that.
Explanation of the code:
We can use windowWillClose instead of windowShouldClose too. Which one to use? Well both should work fine, unless your app does something specific on both events.
Difference between windowWillClose and windowShouldClose is:
- windowWillClose is triggered when the window is closing, due to any reason, it’s just closing.
- windowShouldClose is triggered when the intent to close the window is expressed. E.g. when the user clicks the window close button. This should then ideally lead to windowWillClose event itself too, however can be halted in various situations or custom code too.
Also note, that the sender can be both Any or NSWindowDelegate too.
Complete code
The complete code (excluding your own and other required code of the class) will look like this:
class ViewController: NSViewController, NSWindowDelegate { // ... rest of the code goes here override func viewDidAppear() { self.view.window?.delegate = self } func windowShouldClose(_ sender: Any) { NSApplication.shared().terminate(self) } }
Note: The code above has to be added. Any other code of your class should still remain there and work as it needs to.
I hope this will help you understand how to make your applications close properly when the windows close button is clicked in your xcode cocoa app, using swift 3.0.1 code. If you have any queries or corrections and improvements to this tutorial, please let me know through comments.
Hi there,
thanks for this post.
I tested it on Xcode9.1 and doesn’t works properly.
Any suggestion?
Thanks in advance
Please tell me the issue that you’re facing in detail.
It’s simpler to just add the following to the AppDelegatte:
Thanks for sharing the code!