I use code like the following (inside my appController.m for example) to do some cleanup when my application terminates...
- (void) dealloc {
[myObject release]; // myObject 's dealloc will not be called either !!!
[arraySMSs release];
[super dealloc];
}
This method never get called when the app quits! Why ? Is there a better place to do my clean up ? The fact that is not called addresses memory-leak issues ? Or the OS does take care of clean up ?
Thank you...
There is no reason for the system to ensure that every object is individually deallocated upon application termination.
Doing so is just a waste of CPU cycles and a waste of the user's time.
When an app is terminated, all resources used by that app are reclaimed by the system in an entirely automatic and unavoidable fashion.
If you need something to happen at app termination, use the application delegate's hooks for doing so. But don't rely on that. A user may force reboot a device or force quit an application at whim.
Here's the quote from NSObject Reference:
"Important: Note that when an application terminates, objects may not be sent a dealloc message since the process’s memory is automatically cleared on exit—it is more efficient simply to allow the operating system to clean up resources than to invoke all the memory management methods."
It pretty much confirms what many people have said.
nice question, i was confused too.
now i got this:
Said that there's no object managed by our custom code that owes the appDelegate class itself, we don't really need to worry to "release" its instance.
UIApplication is the only class that retain it, but we don't owe it.
But, for academic discussion or if there's any purpose i don't know at the moment,
when you wanna test the dealloc in your appDelegate class:
applicationWillTerminate is the right place to know if your app is going to quit.
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[UIApplication sharedApplication].delegate = nil;
// after this, the dealloc method of our appDelegate class will be called
}
What makes you think dealloc is not being called? Have you run this is the debugger? Please see this question for why you won't necessarily be able to call NSLog in the dealloc method: when is dealloc executed?
Related
Is dealloc guaranteed to be called on the same thread that created a NSObject instance? For example, if I call [[MyFluffyBunny alloc] init] on the main thread, is dealloc guaranteed to also be called on the main thread, or can it be called on any thread once MyFluffyBunny is no longer retained?
I see sporadic crashes in my app that points to that it's not guaranteed, but I've been unable to find any documentation confirming it.
The object is deallocated on whatever thread releases the last strong reference to it. That is, whatever thread calls -release the final time. It is actually during that -release call that the object is deallocated.
The documentation for the -release method in the NSObject protocol says:
Decrements the receiver’s reference count. … The receiver is sent a dealloc message when its reference count reaches 0.
The Advanced Memory Management Programming Guide: Practical Memory Management article includes this among the reasons to not use -dealloc to manage scarce resources:
Cleanup logic being executed on the wrong thread.
If an object is autoreleased at an unexpected time, it will be deallocated on whatever thread’s autorelease pool block it happens to be in. This can easily be fatal for resources that should only be touched from one thread.
There is no such guarantee and, in fact, it makes for some subtle bugs when using KVO (and bindings on OS X).
You can see it in action fairly easily by creating an object that logs [NSThread currentThread] during init and dealloc, then running code such as:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Testing *testing = [[Testing alloc] init];
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
NSLog(#"Use testing in background: %#", testing);
});
testing = nil;
return YES;
}
I'm unaware of a line in the documentation that says anything about this, but here are some points of logic:
If you can't find a guarantee somewhere, assume it doesn't exist. (It sounds like you're aware of this already, and are hoping beyond hope that somebody else can point you to something that gives you the answer you want)
That requirement cannot be possible because you can construct something on a thread, then end that thread, then have the last reference go out of scope somewhere else in some other thread. It wouldn't be possible at this point to dealloc on the old thread because it no longer exists.
I do not clean up singleton objects that live the life of the application in the dealloc. Is there any reason I should?
- (void) dealloc
{
// never deallocs
[super dealloc];
}
I'm kind of assuming that the iOS has me sufficiently walled off to clean all of my app's memory up when it ends. Is that right?
Yes, when your app is terminated, your app's virtual memory address space will be completely wiped/freed. You can fill out -dealloc if you want, but it will never get called, so the only advantage to doing so is that if you decide to make your object a non-singleton down the track, you've got the dealloc method there already.
One thing to keep in mind is that any singleton (which will exist for the entire life of your app) that has any kind of cache that could reach a large size should register for the UIApplicationDidReceiveMemoryWarningNotification, and reduce or flush the cache as appropriate when a memory warning occurs.
Where is the best place to invoke removeObserver:name:object: since the dealloc method does not always be executed as mentioned in NSObject class reference ??
If you're referring to this note:
Important: Note that when an application terminates, objects may not be sent a dealloc message since the process’s memory is automatically cleared on exit—it is more efficient simply to allow the operating system to clean up resources than to invoke all the memory management methods.
It says dealloc is typically not guaranteed to be called only on application termination. So even if dealloc isn't called, the resources used by your application will still be cleared by the OS. That means all your objects will be gone anyway because your application isn't there anymore.
Therefore, the best place to remove a notification observer from the notification center is still within the observer's dealloc method.
I inherited an iPhone app at work and I'm new to Objective-C so I don't have my bearings just yet. I encountered code similar to this:
- (void) dealloc {
[[StaticObject sharedObject] showSomeDialog];
[super dealloc];
}
I know this is frowned upon in other languages. My spider sense is going crazy looking at that code.
Is this a common Objective-C idiom? Or do I have a crappy codebase to fix?
You should not put UI code in a -dealloc. General rule of thumb, only use -dealloc to clean up what you've done: release objects, remove observers, etc.
Consider what would happen if this object lived on a thread other than the main thread... now you'd have UI code running on the non-main thread, which is a bad thing.
You can do such thing for some debugging reasons. But I don't think you should ever do anything like this!
This means a dialog is prompted when an object is being deallocated. So if you need any mechanism to show a dialog at a certain time don't make it depended on an object being deallocated.
In the dealloc method you should really just release all objects retained by the deallocated object. And not doing some fancy application features.
I have a Cocoa interface. When I press a button I want to process some data, but I want to keep using the interface while it's working. I guess the only solution is NSThread. Now will there be a locking mechanism preventing me from returning from an IBAction method if it spawns a thread?
No, there is no locking mechanism. The new thread will start and the current thread will continue. You may want to look at performSelectorInBackground:withObject: and possibly NSOperation in addition to NSThread.
Take a look at NSOperation. NSOperation is one of the few cocoa classes which must be subclassed for it to be useful. By adding a delegate property to your NSOperation subclass you can get notified when the operation completes. Also, you can add a userInfo property to allow the operation to pass back arbitary data to the delegate
#implementation MyNSOperationSubclass
-(void)main
{
//do operation here
//operationResult is used to report back to the delegate. operationResult could include a userInfo key so that the delegate can have some data passed back, or an error key to indicate success of the operation.
NSDictionary *operationResult;
//Some checks to ensure that the delegate implements operationHasFinished: should be added.
//waitUntilDone: YES locks the main thread
[[self delegate] performSelectorOnMainThread:#selector(operationHasFinished:) withObject:operationResult waitUntilDone: YES];
}
#end
Don't know much about cocoa, but starting a new thread for processing something in background while keeping the UI thread free for taking user inputs(and thus preventing UI from freezing) is the most widely used technique for the problem you have mentioned.Both threads will work together (concurrently) and the programmer has to take care of the synchronization issues if any.You should go ahead with the technique without doubt.
Thanks,
Sourabh