How to quit cocoa app when windows close? [duplicate] - objective-c

This question already has answers here:
Make a Cocoa application quit when the main window is closed?
(5 answers)
Closed 9 years ago.
I need to quit Cocoa App when I click the red button on upper left.
I found this page saying
So what you need to do first is have the window you want to close be
connected to an IBOutlet in the nib. For this example i connected the
window to an outlet named "mainWindow".
How can I do this? I found Windows in xib file, but how can I connect it to an IBOutlet in the nib?
Or, is there any way to quit the cocoa app clicking red button?
EDIT
I should have put the code in the automatically generated delegate file.

There is an optional method for the application's delegate which will do this automatically. All you have to do is add this to the implementation. You don't need to create an outlet or anything.
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
return YES;
}

Take a look at the NSApplicationDelegate protocol, especially to the applicationShouldTerminateAfterLastWindowClosed:method...
http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.html

Related

How can I delegate one NSViewController from another NSViewController in ObjC on Mac? [duplicate]

Hi I've seen this question asked a few times already but with no definite answer yet so I created it for xcode 7 and swift2 (which may have changed things a bit anyway).
I created a project using Xcode 7 and Cocoa OSX Story boards + swift2, so my project started with a NSWindowController that Connects to a NSViewController (as expected!). I added a NSToolbar to my window controller and added a NSButton to the toolbar. I changed my NSViewController to be one of the new NSSplitViewController that links to three NSViewControllers and displays their views horizontally - with vertical dividers - (similar to the layout you see in the photo app or pages in Yosemite +). My final goal will be that the button in My toolbar shows and hides the first split.
It is my understanding is, and I would expect that to achieve this I should create an action in the NSSplitViewController that changes the auto layout constrains more or less in the way they are working it out here: How to do collapse and expand view in mac application?.
And then somehow link this action to the NSButton that is in the Toolbar... which happens to be in the NSWindowController (far up and isolated in the hierarchy)...
I have already gone through other questions about NSToolbar and storyboards and failed to accomplish my goal:
The YouTube video: Cocoa Programming L17 - NSToolbar which is the closest I found to solve the problem, but his method does not work for storyboards, only creating your own xib file.
In this question: How to use NSToolBar in Xcode 6 and Storyboard? One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...). A second person suggested to create a view controller variable in the NSWindowController and manipulate its properties from there... but again, a bit dodgy too.
One latest comment I saw in that question which seems the best way to tackle the problem (but still not as good as I guess it could be) is to add a NSObjectController to the dock of each scene and when the scene loads, set the values of the objects to the other secene's controller. Is this really the best way to go ahead? If so, how could I achieve this one?
Apple did mention (again) in WWDC15 that they created storyboards for osx and the split-view controller that owns view-controllers so that you can move your logic and work to the specific view-controller, so I would be expecting to do everything from inside my split-view controller as this is the target that needs to change.
Does anyone know how to achieve this from the view controller itself? I really haven't been able to find a way to connect my ToolBarItem to it.
OK, I've created this question quite a few days ago and no answer so far so I've answer with what I recently did to overcome the problem.
After I created my Xcode project I did this:
Created a subclass MySplitViewController for the NSSplitViewController
Added an IBOutlet for each NSSplitViewItem. For example:
#IBOutlet weak var mySplitViewItem: NSSplitViewItem!
Created a subclass WindowController for the NSWindowController
Added an IBAction in the WindowController class that links to the NSToolbarItem (my button)
Added a property that gets the Window Controller's content as MySplitViewController
var mySplitViewController: MySplitViewController {
return self.window?.contentViewController as! MySplitViewController
}
Now I can access the split view controller's property from the Window Controller in the action I created:
mySplitViewController. mySplitViewItem.collapsed = true
I created some sample code that does this (but using a view controller and changing the text for a label here, just in case someone wants to see a working project with this behaviour. And a blog post about it too :)
One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...).
I think this first responder method is actually the proper way.
As an example:
Add something similar to the following, in whichever view controller makes sense.
#IBAction func doSomething(_ sender: AnyObject?) {
print("Do something.")
}
This will magically show up in the first responder:
In your storyboard, right-click the orange "first responder" icon above your window controller, and you should see doSomething in the very long list. You just need to connect that up to your toolbar button.
In the following screen capture, you can see my "Toggle Sidebar" button is connected to the toggleSidebar action in my first responder.
I didn't even have to write this method — it's provided by NSSplitViewController:
#IBAction open func toggleSidebar(_ sender: Any?)
So, I was working this same issue and finding no solution as you experienced. I read your post and was trying to figure how I would implement your solution when it occurred to me to use a notification. In about 30 seconds, I had a perfectly fine working solution:
In your windowController add an IBAction to post a notification like so
-(IBAction)toggleMasterViewClicked:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:nil];
}
Hook up that action to your NSToolbarItem, then in the viewController add self as an observer for that notification like so
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(toggleMasterView:) name:#"TestNotification" object:nil];
In your case, selector would be updateMyLabelText
I don't really see any downside here. No reference to other objects needed, no dependancies. Works flawlessly for me
While connectiong IBActions works by using either the First Responder or by adding an "Object" to the scene, then changing its class to the window's view controller class, this doesn't help with IBOutlets and delegates that you'd like to point to the view controller.
Here's a work-around for that:
Add the Toolbar to the View Controller, not to its Window. That way, you can make all the IBOutlet connections in the View Controller Scene easily. I've done that for years and found no issues with it, even when using Tabs.
You'll have to assign the window's toolbar in code, then. E.g. like this:
#interface ViewController ()
#property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
#end
- (void)viewWillAppear {
[super viewWillAppear];
self.view.window.toolbar = self.toolbar;
}

Where is my closed NSWindow?

I have an Application delegate that holds the reference to a NSWindow and the program (small test program so far) is generally working with Main Menu and views in the window.
However I discovered that if I close the window holding the views it's gone although the program is still running. As far as i can see the window reference is not nil but how do I restore it so it's visible and shown under the Windows menu again?
The program is not document based. All actions are performed in the window in question.
I created the window in the MainMenu.xib that was auto created by Xcode (this was in Xcode7 or 8 but now I've upgraded to 9).
I'm new to windows handling on Mac so I understand this is a very basic question but I'm totally stuck here. Having a window that is supposed to hold all functionality disappear without the user being able to restore it is bad I believe.
If you have a reference to the NSWindow, you just need to show it. For example:
[window makeKeyAndOrderFront:self];
But if the user closed the single window of your app, than the question is: How will the user trigger that code? The simplest answer is that the user will click your app's icon on the dock. To handle that click, implement the following method on you app delegate.
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)hasVisibleWindows
{
if (hasVisibleWindows) {
return YES;
}
[window makeKeyAndOrderFront:self];
return NO;
}

Can IBOutlets be used in App Delegate to access Document windows?

Forgive me if this is obvious, but I'm very new to Cocoa and Objective-C.
I have a very simple Text Editor app that has two windows created using Interface Builder. One for the text content, and another window with various controls and an "Enter full screen" button.
I have an IBOutlet called myWindow defined in the App Delegate, linked to the text editor window. I use:
[self.myWindow togglefullscreen]
in the App Delegate to enter full screen mode when "Enter full screen" button is pressed on the other window.
Now, I am trying to convert my application into a Document Based Application.
My question is: how do I access the current Document's window so I can call togglefullscreen on it, from within the App Delegate? Is this even possible/elegant?
Interface builder won't let me connect the IBOutlet in the App Delegate to the Document window in Document.xib which I guess makes sense as there could be multiple instances of it.
Another question that stems from this is, should this full-screen functionality be implemented in the Document class, and should the "Full Screen" button be on the Document window itself (as only one document will ever be full-screen)?
Any ideas would be much appreciated :-)
John
An NSDocument (sub-class) can have more than one window associated with it. Your NSDocument sub-class can access NSDocument's windowControllers property to get an NSArray of windowControllers (IIRC back to front order) and ask each one for it's associated window (property).

Not loading the window from the MainMenu.xib, instead load another window

This is my first Mac OS-X app, so this might be a stupid question.
In my app basically i have two windows,
The Main window which comes with MainMenu.xib file by default
I created another WindowController with another xib file.
I have created a AppController class which is connected to the MainMenu.xib, what i am trying to do in the awakeFromNib method in the AppController class is load either the main Window or the custom window, but load the Main Menu each time. Is it possible?
I couldn't do it the previous way, if i needed to use the custom window, i would first create the main window and close it immediately.
I tried to get the main window by this, [[NSApplication sharedApplication]mainWindow]; and then closing it. But was unsuccessful.
I dont think i have proper understanding yet with windows, views and controllers of cocoa. i am following aaron hillegass's COCOA Programming for Mac OS X book.
please suggest me some other tutorials so that i can understand this thing clearly.
You need to un-check the windows "Visible at Launch"
Then based on your BOOL value, you need to show the window and make it orderFront.

Window-less Cocoa application

I'm a complete beginner in Objective-C and Cocoa.
I would like to create a window-less application, which just shows a NSStatusItem in the system tray. The tray works fine, however, there is one problem.
For some reason my application automatically creates a window for me, which I do not want.
I thought it was caused by the automatic Interface Builder template created when I created the application in Xcode, so I deleted the .nib file from the project. However the window still gets created.
The only lines that contain a reference to the window are in the header:
NSWindow *window;
#property (assign) IBOutlet NSWindow *window;
and in the implementation file:
#synthesize window;
Both were added automatically, I did not write this.
How do I just stop the app from creating a window? I even tried to removing all references to window from the code, including the NSWindow *window, but the window still got created.
My temporary fix right now is to call [window close]; in the application, but surely there is a better way?
My suspicion is that nothing in your code is creating the window. When you create a new Cocoa Xcode application, Xcode sets up an XIB with your interface for you. Open up MainMenu.xib (should be under Resources) in interface builder and delete the window that it throws in by default.
If you don't want to show a window you may consider run your application in background. That will stop the window to appear.
In order to run your application in the background, set YES to "Application is background only" in your app's PLIST file
Return false in your NSDocument subclass' windowNibName method.