I want to save my data before terminating, so my AppControll class conforms the NSApplicationDelegate protocol, and declared the method; and in the interface builder I bound the window's delegate outlet to AppController, but I cannot get the method invoked.
Where I am wrong, what should I do?
Are you terminating the app from Xcode? Alternatively, is sudden termination enabled in your Info.plist?
Either of these will cause a SIGTERM signal to be sent to the application, terminating it immediately, with no chance for the NSApplication instance to send its delegate an applicationWillTerminate: message. (This is the point of sudden termination: Your app dies instantly. You can turn it off and on programmatically for times when this would be bad.)
Try quitting your application within itself (the Quit menu item in your Application menu), or using the Dock to quit it (right-click on your application's tile and choose “Quit”). As long as sudden termination is disabled (or never was enabled), either of these will cause your application object to send the applicationWillTerminate: message.
Also check that your delegate is getting sent other application-delegate messages, such as applicationWillFinishLaunching:, and make sure you hooked up the outlet in the correct nib (your MainMenu nib).
Did you remember to add the handler to the application?
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification object:app];
Is multitasking still enabled? That could be the problem - tapping the home button doesn't cause applicationWillTerminate: to be called if the app goes into the background.
I'm assuming this question applies to macOS apps (as it mentions NSApplicationDelegate).
By default, Xcode 11 (and maybe earlier versions?) includes the NSSupportsSuddenTermination property in new applications' Info.plist file:
...
<key>NSSupportsSuddenTermination</key>
<true/>
...
This property is associated with the enableSuddenTermination and disableSuddenTermination pair of methods in the ProcessInfo (NSProcessInfo) class.
The relevant part of ProcessInfo documentation states:
Sudden Termination
macOS 10.6 and later includes a mechanism that allows the system to log out or shut down more quickly by, whenever possible, killing applications instead of requesting that they quit themselves.
Your application can enable this capability on a global basis and then manually override its availability during actions that could cause data corruption or a poor user experience by allowing sudden termination. Alternately, your application can just manually enable and disable this functionality.
In other words, when NSSupportsSuddenTermination is true, when the user tries to quit the application (directly or indirectly), macOS terminates it, instead of requesting it to quit. This bypasses any events that would otherwise be triggered during a regular quit request.
The good new is that you can either disable that in the Info.plist file, or manually override it, according to your application's needs, by calling ProcessInfo.processInfo.disableSuddenTermination().
In applicationWillFinishLaunching: add:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification object:nil];
Related
Coming from a .NET background I'm used to events getting fired so trapping a lost focus event is easy but I'm not sure how to do this in Obj-C. Basically I want my app to know when another application has gotten focus and it no longer has it so it can perform some actions.
Can you please tell me how I can implement this kind of functionality in Obj-C for an OSX app?
Have a look at the NSWindow notifications. Specifically, you're interested in NSWindowDidBecomeKeyNotification and NSWindowDidResignKeyNotification. You can also create a delegate for the window and implement its windowDidBecomeKey: and windowDidResignKey: methods, as noted in the NSWindowDelegate protocol documentation.
Or, if you just wanted to know when the application (not a window) has gained focus, you can subscribe to the NSApplicationDidBecomeActiveNotification. Likewise, NSApplicationDidResignActiveNotification will notify you when your app loses focus. These notifications are discussed more here. You can also implement applicationWillBecomeActive: and applicationWillResignActive: in the application delegate.
It's unclear if you want notification of a single window losing focus or notification of your entire app losing focus. My answer here provides notification for the entire application losing focus. (See mipadi's answer if you just want to know when one of your app's window loses focus.)
Observe the appropriate notification:
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(appDeactivated:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
Then add the handler method:
-(void) appDeactivated:(NSNotification *)notification
{
NSRunningApplication* app = [notification.userInfo objectForKey:#"NSWorkspaceApplicationKey"];
if (app == [NSRunningApplication currentApplication]) {
// your cleanup code here
}
}
I would like to perform certain cleanup tasks when the app shuts down. I use an observer like:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appWillResignActiveNotif:) name:UIApplicationWillResignActiveNotification object:nil];
to get notified when the app goes to background.
The problem is that if the app crashes, there is no notification for me to do something.
I saw that testflight.com use a hook to recover crash information, I was wondering if it was possible to also detect crashes and perform some tasks.
My concern is regarding the call to:
CLLocationManager.stopMonitoringSignificantLocationChanges
not being done when app crashes, leaving users with a constant location icon on top. I know that crashes are not supposed to be frequent, but would like to clean as much as possible if I can under these circumstances.
you could install a global exceptionHandler or even a signalHandler
http://www.cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html
but remember: dont continue running after a crash. it is NOT safe :D
I am developing an iOS application where need to do some stuff when I have Internet connection and other, when I haven't. If I haven't at some point I will show a message to the user to give me internet and come back. The question it is how to detect the following situation:
the user press the Home button twice, goes to multitasking , Settings and will connect to internet
the user comes back with multitasking to my app, but doesn't press anything
I know I will get callbacks to the AppDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void) applicationDidBecomeActive:(UIApplication *)application
but the code ( it is not started by me) it is very big, and I don't want to handle there the UIViewController needs, if there is any alternative.
My UIViewController's - (void)viewDidAppear:(BOOL)animated it isn't called when the user came back.
The breakpoint it is not hited for sure!
Any usable ideas, except in AppDelegate?
You can use the notification center to listen to applicationDidEnterBackground within the view controller:
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleEnteredBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
Do this in viewDidLoad. Similarily for applicationDidBecomeActive.
Don't forget to remove yourself as an observer in viewDidUnload.
The application delegate is the correct place to be handling application state changes, but just because that is the case, it doesn't mean you must put all the logic that is triggered by the application state change in there.
Put the logic where it belongs. If it's networking code, that's not in the application delegate and it's not in the view controller, it's in a separate class. Then look into ways of tying the different parts of your application together. In most cases, notifications, KVO and the shared instance pattern are good approaches to take.
I found this method in a delegate file and inserted some code. The code never gets executed, even when the home button is pressed. When or how does this function get called?
You should use applicationDidEnterBackground method if your app and OS support multitasking.
From applicationWillTerminate docs:
For applications that support background
execution, this method is generally
not called when the user quits the
application because the application
simply moves to the background in that
case. However, this method may be
called in situations where the
application is running in the
background (not suspended) and the
system needs to terminate it for some
reason.
I have some code that needs to be run when the application terminates. I register my controller for the NSApplicationWillTerminateNotification as follows:
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: #selector(applicationWillTerminate:)
name: NSApplicationWillTerminateNotification
object: nil];
Now, if I start my app and quit it within the first 20 seconds or so, applicationWillTerminate gets called. If I quit the application later, it doesn't. What in my application could cause this behaviour? I have also tried to set up my controller as NSApplication's delegate with same results. Any ideas?
Thanks.
Oh, and this is XCode 3.2, Snow Leopard 10.6.1, using 10.5 SDK. Happens in both Debug and Release builds.
There are several reasons why this might be happening.
If you are running GC'd, does your observer get collected and finalized before the termination happens? (I should test this and file a bug if it does as that at least needs to be documented)
Is your app silently crashing or calling exit() directly?
In general, you cannot count on the termination notification being received as the user might go for a force quit for the heck of it.
Also, in Snow Leopard, there is a feature called sudden termination that allows your app to let the system know that it is safe to kill the app instead of going through the normal termination rigamarole. It is documented in the NSProcessInfo documentation.