NSApplicationWillTerminateNotification not received - objective-c

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.

Related

NSWorkspaceDidActivateApplicationNotification called before application is ready to use (launched)

I'm using both NSWorkspaceDidActivateApplicationNotification and NSWorkspaceDidLaunchApplicationNotification notifications to know which app the user is interacting with.
The problem is that, if an application is just opened and still launching, I first receive a activate notification, and soon afterwards a launch notification.
Is there any way to know within the activate method that the app is still launching and not yet ready for use? (Still bouncing in the dock)
I see that the ichat sample project by apple does not use the above approach and instead only listens to launch notifications. It then uses kAXApplicationActivatedNotification to add an AXObserver to the app. Is this the preferred way? (And also NSRunningApplications to add an observer to all already loaded apps).
I wanted to keep using just plain simple NSNotifications because I think it may be less memory intensive. (No need to keep an observer around for each and every app loaded).
check the NSRunningApplication object passed in the userinfo of the NSWorkspaceDidActivateApplicationNotification
NSRunningApplication *app = [note.userInfo objectForKey:NSWorkspaceApplicationKey];
if(app.isFinishedLaunching)
NSLog(#"up");

iOS 5 - shutdown hook

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

EAAcessory errors while closing session with iOS 6.0 GM

There is a MFI device that is connected to iPhone 4S (6.0 GM) or to iPad (6.0 GM) via Bluetooth (2.1 + EDR). The project was built on Xcode 4.5 GM. When the app gets EAAccessoryDidDisconnectNotification it will send message [_eaSessionController closeSession];. All these worked nice in iOS 5.1.1 or earler. But on iOS6 with this message I got logs as follows:
-[NSCondition dealloc]: condition (<NSCondition: 0x2e5640> '(null)') deallocated while still in use
Break on _NSLockError() to debug.
Any ideas?
I came across the same issue. This warning is thrown when calling [NSStream close] upon receiving an EAAccessoryDidDisconnectNotification. There should be also some data exchange between the two devices just before the disconnection.
Breaking on _NSLockError will show that at the moment the object is deallocated, some of the threads spawned by the external accessory framework are waiting on conditions. One of those certainly waits on the condition that is being freed, which explains the warning thrown on the console.
I also noticed that the number of threads created by the external accessory framework keeps on growing each time the accessory disconnects then connects, and they seem to be just leaking.
It seems to me that somehow, the external accessory framework does not properly free the resources it allocates, which results in a lot of mess. One of the subsequent effects of this are crashes that happen inside one of those leaked threads during a call to OSAtomicCompareAndSwap64.
I managed to reproduce the issue using a basic sample in which the streams are scheduled on the main thread to avoid any thread management inside the application. I believe it's an accessory management bug on iOS 6 that Apple should be aware of. I'll report it and wait for what they have to say.
Meanwhile, I wonder if anyone of you guys has managed to make any progress on this.
Thanks,
There is no such trouble in iOS 6.1+. To fix this for iOS 6.0 and iOS 6.0.1 please use next solution:
Please note: this is only temp solution allow your users with iOS 6.0 and 6.0.1 continue use your app.
There is a simple hack to avoid application crashes: just create new category and override dealloc method (NSCondition) for iOS 6.0 and iOS 6.0.1:
#import "NSCondition+LeakDealloc.h"
#import <objc/runtime.h>
#implementation NSCondition (LeakDealloc)
- (void) safeDealloc
{
float sVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (sVersion < 6.0 || sVersion >= 6.1)
{
[self safeDealloc];
}
}
+ (void) load
{
method_exchangeImplementations(class_getInstanceMethod(self, #selector(dealloc)), class_getInstanceMethod(self, #selector(safeDealloc)));
}
#end
This solution make new leak, after 20 min tests and about 50 BG/FG swithces instruments shows 10 NSCondition leaks (960 Bytes), BUT no one crash!
The issue has been fixed in iOS 6.1.
There are no more leaking NSCondition or external accessory threads. Apple seem to having fixed the issue properly.

NSURLConnection and multitasking in iOS

I'm using NSURLConnection to download resources asynchronously in iOS. (They are large-ish PDF files, so it takes some time on a slow connection.)
Now I'm updating my app from iOS 3 to iOS 4. As my app is none of location-aware, voip, and background music, I guess I need to do something.
My question is, then, what happens to the NSURLConnection currently running? Is it suspended and magically resumed when the app comes back to the foreground, or is it outright killed? If it is the latter, what is the standard strategy to resume it automatically later? Is there a open-source subclass of NSURLConnection which automatically does that?
You can start a task that will run for at most 10 minutes. Look at using the beginBackgroundTaskWithExpirationHandler: API for this purpose. Just be aware, if your task takes too long, it will be killed by the OS.
The NSURLConnection is indeed suspended and started again when the app enters the foreground. Just make sure you kill the connection if the app moves from suspended to not running like so:
- (void)applicationWillTerminate:(UIApplication *)application {
if (self.downloadConnection != nil){
[self.downloadConnection cancel];
}
}

applicationWillTerminate does not get invoked

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];