applicationDidHide - Not Getting Triggered?

  • Apologies for a newbie question.

    I've just tried my first normal Mac application in Xcode (so far I had
    only created an iOS app and a Mac screensaver).

    Everything went fine (after I fixed an incorrect alloc), but it's what
    happens at the end of the app's (apparent) lifetime that has got me
    slightly bemused. I'm running this under the debugger, if that makes a
    difference.

    If I Command-Q the main window, the debug session terminates as
    expected. If I only click the close button, the window vanishes but
    debugging doesn't stop. It took me a few minutes to figure out that this
    wasn't something dumb I'd done, but standard Mac app behaviour, whereby
    it hides for fast startup next time rather than actually quits (I
    *think* I've got that right?).

    To confirm that that was what was happening, I tried to trap
    applicationDidHide: - so I literally added

    - (void)applicationDidHide:(NSNotification *)aNotification
    {
    }

    into the delegate's .m file. I'm confident that I don't need anything to
    match in the .h file as this is an override, and
    applicationDidFinishLaunching: isn't in the .h file either.

    I have a breakpoint in there (on a dummy variable initialisation), but
    it doesn't get hit when I click the main window's close button.

    Have I misunderstood something?

    Thanks in advance.

    --
    Jason Teagle
  • On May 19, 2012, at 3:48 AM, Jason Teagle wrote:

    > Everything went fine (after I fixed an incorrect alloc), but it's what happens at the end of the app's (apparent) lifetime that has got me slightly bemused. I'm running this under the debugger, if that makes a difference.
    >
    > If I Command-Q the main window, the debug session terminates as expected. If I only click the close button, the window vanishes but debugging doesn't stop. It took me a few minutes to figure out that this wasn't something dumb I'd done, but standard Mac app behaviour, whereby it hides for fast startup next time rather than actually quits (I *think* I've got that right?).
    >
    > To confirm that that was what was happening, I tried to trap applicationDidHide: - so I literally added
    >
    > - (void)applicationDidHide:(NSNotification *)aNotification
    > {
    > }
    >
    > into the delegate's .m file. I'm confident that I don't need anything to match in the .h file as this is an override, and applicationDidFinishLaunching: isn't in the .h file either.
    >
    > I have a breakpoint in there (on a dummy variable initialisation), but it doesn't get hit when I click the main window's close button.
    >
    > Have I misunderstood something?

    Hiding an app is a specific operation that's not related to quitting it or closing its last window.  There's a Hide <App Name> menu item in the application menu (the one named after the application).  It's also available from the Dock context menu.  Also, when another app is active, the user can do Hide Others, which would hide your app.

    *That* is when -applicationDidHide: would be called.

    Closing the last window of an application doesn't automatically quit it unless the app delegate implements -applicationShouldTerminateAfterLastWindowClosed: to return YES.  The app is still running and current.  Its menu is shown in the menu bar and you can still use it.  Among other things, you may use it to open a new document (assuming it is document-based).

    Under Lion, there can be a disconnect between the apparent running state of your app and the real one.  Lion may show an app as running when its process has actually been terminated.  It may also make it seem that an app which had no windows open and was not current has quit when it's actually still running.  In the first case, resources are freed up.  It is assumed that the app can restore its state, so the illusion that it was running all along is harmless to the user.  In the second case, the UI is simplified but "restarting" the app is basically instantaneous because it was always running.

    For this to happen, your app has to claim to support automatic termination, either by putting the NSSupportsAutomaticTermination key in the Info.plist or by invoking -[NSProcessInfo setAutomaticTerminationSupportEnabled:].

    Regards,
    Ken
  • > Hiding an app is a specific operation that's not related to quitting
    > it or closing its last window.  There's a Hide<App Name>  menu item
    > in the application menu (the one named after the application).
    >
    > *That* is when -applicationDidHide: would be called.

    Ah... so there is. My bad. All part of the learning process.

    > Closing the last window of an application doesn't automatically quit it
    ...
    > The app is still running and current.  Its menu is shown in the menu bar
    > and you can still use it.

    This time I noticed that even though I'm running under the debugger,
    there is an icon in the dock; the icon looks just like Interface
    Builder's so I didn't realise it was mine!

    This seems to be a problem though - clicking on it won't bring my main
    window back. Am I supposed to respond to something here? As my app is
    still running I assumed it would come back up automatically as if it had
    simply been minimized rather than closed.

    I realise there is a wealth of documentation out there so if I'm asking
    questions that are better answered by reading something in particular,
    please let me know. I've read quite a bit as I'm going along but it
    looks like I should start reading up on app lifecycles. I had it easy
    with the screensaver as the work was done for me - and on the iPhone it
    'just worked'.

    > Under Lion, there can be a disconnect between the apparent running
    > state of your app and the real one.  Lion may show an app as running
    > when its process has actually been terminated.  It may also make it
    > seem that an app which had no windows open and was not current has
    > quit when it's actually still running.  In the first case, resources

    Assuming I don't specifically want to support any of this new behaviour
    at this time (i.e., not actually *trying* to support it explicitly), are
    there any implications for my app that I should be aware of to make sure
    my apps are as future-proof as possible? Best practices that I should
    get into the habit of right now, since I'm learning the ropes anyway? I
    would hate to write a killer first app only to find it dies in flames or
    is buggy as hell under Lion's new regime (I'm still only on Snow Leopard).

    --
    Jason Teagle
  • On May 19, 2012, at 4:46 AM, Jason Teagle wrote:

    >> Closing the last window of an application doesn't automatically quit it
    > ...
    >> The app is still running and current.  Its menu is shown in the menu bar and you can still use it.

    > This seems to be a problem though - clicking on it won't bring my main window back. Am I supposed to respond to something here? As my app is still running I assumed it would come back up automatically as if it had simply been minimized rather than closed.

    It was not minimized.  Apps can't be minimized, only windows can.  Your app was simply running with no windows open.  If it was current when you closed the window, it is still current.  Check the menu bar.  If you've switched away from it, you can switch back with Command-Tab.  It is not expected that doing just that will create a new window.  There's nothing "wrong" with an app that's running without windows.

    When you click on the Dock icon for a running app, it is a "relaunch" or "reopen app" event.  The same is true if you were to go to the Finder and double-click on your app's icon while it was already running.  In this case, it is expected that the app will created a new window if there isn't already a window open.  However, that behavior is not entirely free.  You have to implement some stuff.

    Cocoa handles the reopen event by checking if your app delegate implements -applicationShouldHandleReopen:hasVisibleWindows:.  If doesn't or if it returns YES, then it checks if the delegate implements -applicationShouldOpenUntitledFile:.  If it doesn't or if it returns YES, it calls -applicationOpenUntitledFile: if the delegate implements it.  If the delegate does not and it is document-based, it invokes -openUntitledDocumentAndDisplay:error: on the shared NSDocumentsController.

    So, the short story is to implement -applicationOpenUntitledFile: to do whatever you want, either when your app is first launched or when it is "relaunched".

    This is documented in Cocoa Scripting Guide: How Cocoa Applications Handle Apple Events <https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Scr
    iptableCocoaApplications/SApps_handle_AEs/SAppsHandleAEs.html
    >.

    You may be confused by the default project template for a Cocoa application in Xcode.  In that project, the MainMenu NIB contains a window and that window is "visible at launch" (which really means "visible when the NIB is loaded").  Since the MainMenu NIB is loaded automatically when the app is first launched, the window in that NIB is presented.  You didn't have to do anything in code to get that to happen.

    I feel this makes for a poor template for a first app.  Its apparent simplicity is misleading and results in the sort of confusion you're experiencing.  For example, since the presentation of the window happens automatically when the NIB is loaded, it's hard to see how and why it's happening.  Furthermore, since the MainMenu NIB is not suitable for loading more than once, you can't reopen the window in the same way it was originally opened.  You could reopen it by doing [window makeKeyAndOrderFront:self] from the -applicationOpenUntitledFile: method (assuming the window is *not* configured to Release When Closed in IB).

    In general, windows should be in separate NIBs, each of which should be owned and loaded by a window controller.  If a window is to be loaded at application launch, that should be done in code in the -applicationOpenUntitledFile: method.  That would make it clearer to new Cocoa developers what exactly is going on and how they might go about adding behaviors to an app.

    Regards,
    Ken
  • > It was not minimized.  Apps can't be minimized, only windows can.
    Thank you for this patient and in-depth reply.

    > Your app was simply running with no windows open.

    Understood. A little freaky, coming from a PC perspective, but it is
    something I will get used to.

    > When you click on the Dock icon for a running app, it is a "relaunch"
    > or "reopen app" event.
    ...
    > In this case, it is expected that the app will created a new window if
    > there isn't already a window open.  However, that behavior is not
    > entirely free.  You have to implement some stuff.
    ...
    > So, the short story is to implement -applicationOpenUntitledFile: to
    > do whatever you want, either when your app is first launched or when
    > it is "relaunched".

    Again, understood. I will look at tackling that and make sure I can get
    a replacement window started when necessary.

    > This is documented in Cocoa Scripting Guide: How Cocoa Applications
    > Handle Apple
    Events<https://developer.apple.com/library/mac/#documentation/>Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/SAppsHandleAEs.html>.

    Thanks, I'll give this a good read.

    > You may be confused by the default project template for a Cocoa application in
    > Xcode.  In that project, the MainMenu NIB contains a window and that window is
    > "visible at launch" (which really means "visible when the NIB is loaded").

    I was a little disappointed that a skeleton app project didn't provide a
    handy hook in just before the NIB is loaded, as iOS apps do. I get the
    feeling I'm going to end up building the UI manually in code much of the
    time (I'm familiar with sizeToFit and thus getting the required space
    for controls - that is the core of the iOS project I am working on, a
    conversion from a platform I am writing to turn generic controls and
    behaviour (protocols, in Objective-C-speak) into platform-specific UI
    for easy building of phone apps across multiple platforms).

    > In general, windows should be in separate NIBs, each of which should be
    > owned and loaded by a window controller.  If a window is to be loaded at
    > application launch, that should be done in code in the
    > -applicationOpenUntitledFile: method.

    As a general rule of thumb, then, would you say a developer *should* use
    IB to design the interface, or is manually building a UI with careful
    consideration for size (due, for example, to localization in another
    language) an acceptable practice? I realise there are times when
    manually building is just best, as in my iOS project, but I don't want
    to get into bad habits.

    --
    Jason Teagle
  • >>
    >
    > As a general rule of thumb, then, would you say a developer *should* use IB to design the interface, or is manually building a UI with careful consideration for size (due, for example, to localization in another language) an acceptable practice? I realise there are times when manually building is just best, as in my iOS project, but I don't want to get into bad habits.
    >

    Super attitude you have towards trying to learn the platform.

    I would say, to your last question, for OS X apps a developer *should* design the interface in IB, it's how it was designed to work, there's a sort of expectation that you build with NIBs. You can certainly customize things in code later but starting with the thought "I'll do this in IB" and only going into code if you really find an unusual case where IB just doesn't cut it is a good habit approach.

    For iOS I know that right at the start, code-built UIs were quite common because .. actually I'm not sure why .. a lot of books and articles did it that way so people did it that way when IB would have done some of the heavy-lifting for them. I did it too, my first app, when I look at it now, I see how hard I made life. Now I do what I would do in OS X, I use IB for as much of the interface as I can, especially as now that platform has storyboards which I find helps me. I'm still not averse to dumping a placeholder view I can't build in IB (especially since Apple took away IB plugins) and filling that up that in code when the view loads, but I find myself doing that less and less these days. I possibly have very simple apps.

    If you can use IB, use it. If you can't use it, try one last time to use it, then do it another way. That's what I think at least.
  • On May 19, 2012, at 7:23 AM, Jason Teagle wrote:

    > Thank you for this patient and in-depth reply.

    You're welcome.

    > As a general rule of thumb, then, would you say a developer *should* use IB to design the interface, or is manually building a UI with careful consideration for size (due, for example, to localization in another language) an acceptable practice? I realise there are times when manually building is just best, as in my iOS project, but I don't want to get into bad habits.

    I would say that you should use IB until you hit a case where you can't achieve what you want, or at least can't achieve it "comfortably".  Of course, build a UI in code is "acceptable", it just usually unnecessary.

    Regards,
    Ken
  • Roland said:
    > If you can use IB, use it. If you can't use it, try one last time to use it,
    > then do it another way. That's what I think at least.

    Ken said:
    > I would say that you should use IB until you hit a case where you
    > can't achieve what you want, or at least can't achieve it
    > "comfortably".  Of course, build a UI in code is "acceptable", it just
    > usually unnecessary.

    Good enough for me. I would use the equivalent [to IB] for MFC dialogs,
    VB forms and now .NET forms, so I'll use it for Mac / iOS apps.
    Admittedly I never use a visual builder for Java, but I never really got
    on with the ones available (NetBeans was one I tried, as I recall).

    I did struggle with connectors & outlets with IB - seemed an awful lot
    of work to go to just to add a handler for a button click (I miss the
    days where I could right-click the control and say 'Add Handler' or
    simply double-click it), and every single tutorial I found on the net
    failed to work - but after a bit of perseverance I finally got a handler
    in there (it seems I have to manually add the IBOutlet declaration to
    the controller's .h file before IB will let me drag the connector to it
    - is that normal? I kind of expected to at least be able to get IB to
    create an outlet for me that I could then drag to).

    Onward and upward, as they say...

    Regards,
    --
    Jason Teagle
previous month may 2012 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today