Should -dealloc do anything other than release memory? - objective-c

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.

Related

overriding the dealloc method in objective-c

Can someone tell me what would actually happen if you override the dealloc method in Objective-C? As in would it crash or would it just start leaking memory all over the place. I've been wondering what would happen and why it is necessary to prevent the programmer from using dealloc directly.
And in what case would you had to do something like this?
EDIT: Sorry guys for not being clear. I was mainly talking in terms or ARC type coding.
Overriding -dealloc is an extremely common thing to do in non-ARC code. In fact, you'd be hard-pressed to find a class that doesn't override it.
The key thing to remember, though, is that every single override of -dealloc always ends with a call to [super dealloc].
Of course, in ARC code, overriding -dealloc is far less common. And if you do override it, you don't call [super dealloc], because the compiler will insert that for you. But remember, this is only true under ARC.
Before ARC overriding the dealloc method was very common, you were releasing the ivars the deallocated instance owned. Now, with ARC, is less common, however, you may have to do it in some special cases, like when you de-register an instance from observing with NSNotificationCenter.
The rule you talk about was not to call dealloc directly (not override), that would have usually led to a crash since you were bypassing Cocoa's internal reference counting system.
Edit: Based on your edit, if you call [super dealloc] under ARC, you'll get a compile time error. And if there was no error, it would have probably lead to duplicating the dealloc call, which would have made your program crash.

ARC reference counting dealloc, and release

I am getting a bit confused. I am creating an app with storyboard, and running it on iPad 1. the application uses a lot of memory, so reached the 120mb, crashes. accordingly to what I have understood to remove this problem you need to release, dealloc... the point is that with ARC this should be automatic. In fact if I add for e.g.: [label1 release]; it gives me an error. But this ARC automatic release and dealloc does not seem to work! Is this because there are different ways to release with ARC??
You don't need to manually retain/release/autorelease with ARC. However if you have active references to a lot of unused objects they will still remain in memory. Profile your app with Instruments and it will show you how many objects you're creating of each class and how much memory they're consuming.
With ARC you still need to think about memory usage you just don't need to worry as much about memory leaks.
NSObject *bigMemObj = [[BigMemClass alloc] init];
//This creates the object in memory. In both arc and manual counting the retain count is 1
//Do stuff
//Prior to ARC you would have had to call [bigMemObj release]; before setting the variable to nil
bigMemObj = nil
//With ARC you don't have to do anything. The compiler inserts the release at compile time
Also read the documentation on declaring iVars __strong vs __weak.
Without looking at your code it's hard to identify what is consuming all the memory but hopefully that should help you determine where to start looking.
You should implement #autoreleasePool{} inside each method. In essence, each method will look like the following:
-(void)methodName{
#autoreleasePool{
//do method stuff
}
}
This will ensure that, upon exiting the autoreleasePool, memory is properly released.
I can't vote this back up, otherwise I would. I think Alessandro is asking about ARC vs using release and dealloc, not about what he's loading!
So, Alessandro, your understanding is correct that with ARC you don't release or dealloc. Therefore, those won't work if you're using ARC. Also, there is no alternative to release/dealloc, since ARC doesn't use it.
My suggestion would be to look at what you're using in the app that is taking up all this memory. Do you have a large number of pictures, for example, that are very large? Keep any graphics as small as possible, matching the resolution of the iPad. Especially the iPad 1, which doesn't have the "retina display".
You can use Autorelease pools in ARC. Here is some documentation on when to use them:
NSAutoreleasePool Class Reference
Advanced Memory Management Programming Guide: About Memory Management

How to manage unsafe_unretained ivars/properties?

I started objective-c and iOS a couple of weeks ago (worth bearing in mind), and I apologise in advance for the awful diagram!!
The above diagram shows the structure of my calls to a webservice. Thin arrows denote an object creating another object, whereas thick arrows denote an object holding a strong (retained) reference to the pointed-to object.
I believe that this contains what is called a "circular reference" and will create problems when it comes to deallocating the objects.
I understand that the easy answer would be to replace some of the strong references to weak ones, which I'd love to do, except my project is also targeting iOS 3.2 (not my decision - I can't really change this fact!). So, I think I'm right in saying that I have to use __unsafe_unretained instead, but I'm quite worried about the fact that these won't auto-zero, as I'll end up with EXC_BAD_ACCESS problems when objects get deallocated...
So my problem is firstly that I have circular references. To solve, I would have to use __unsafe_unretained, which leads to my second problem: How to correctly manage these?
A question that might be related is: How does NSURLConnection manage it's strong references? I have heard from various sources that it retains its delegate? So...if I retain an NSURLConnection, (and am also its delegate) and it retains me, this would also be a circular reference, no? How does it get around my problem?
Any advice is very welcome!
Regards,
Nick
When a parent has a reference to a child object, it should use a strong reference. When a child has a reference to it's parent object, it should use a weak reference, aka unsafe_unretained.
By convention, delegate relationships in iOS are usually weak references, so you'll find that most delegate properties on Apple's own classes are declared as unsafe_unretained.
So your controller retains the services that it is using, but the services only weakly link back to the controller. That way, if the controller is released, the whole lot can be safely disposed of without any circular references.
The danger with this is that if the web service is doing some long-running task, and the controller gets released before it has finished, the service is left with a dangling pointer to it's now-deallocated delegate. If it tries to send a message to the delegate, such as "I have finished" it will crash.
There are a few approaches to help solve this (they aren't mutually exclusive - you should try to do them all whenever possible):
1) Always set the delegate properties of your services to nil in your controller's dealloc method. This ensures that when the controller is released, the delegate references to it are set to nil (sort of a crude, manual equivalent of what ARC's weak references do automatically).
2) When creating your own service classes that have delegates, make them retain their delegate while they are running and then release the delegate when they are done. That way the delegate object can't get deallocated while the service is still sending it messages, but it will still get released once the service has finished (NSTimer's and NSURLConnections both work this way - they retain their delegate while they are running and release it when they are done).
3) Try not to have long-running services owned by something transient like a view controller. Consider creating singleton objects (shared static object instances) that own your services, that way the service can do it's job in the background regardless of what's going on in the view layer. The controller can still call the service, but doesn't own it - the service is owned by a static object that will exist for the duration that the app is running, and so there's no risk of leaks or premature releases. The service can communicate with the controller via NSNotifications instead of delegate calls, so there is no need for it to have a reference to an object that may vanish. NSNotifications are a great way to communicate between multiple classes without creating circular references.
All of your questions and concerns are correct, and this problem with the previous use of assign (now better named __unsafe_unretained) is why Apple developed auto-zeroing for weak. But we've dealt reasonably safely with assign delegates for many years, so as you suspect, there are ways to do it.
First, as a matter of practice, you should always clear yourself as the delegate when your release an object you were delegate for. Pre-ARC, this was traditionally done in dealloc:
- (void)dealloc {
[tableView_ setDelegate:nil];
[tableView_ release];
tableView_ = nil;
}
You should still include that setDelegate:nil in your dealloc if delegate is __unsafe_unretained. This will address the most common form of the problem (when the delegate is deallocated before the delegating object).
Regarding NSURLConnection, you are also correct that it retains its delegate. This is ok because it has a lifespan typically much shorter than its delegate (versus a table view delegate which almost always has the same lifespan as the table view). See " How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C " for more discussion on this in a pre-ARC context (the same concepts apply in the new world of strong/weak).

after self released

I'm using a third-party Objective-C library that makes a web request in a background thread, then returns the result by using [self performSelectorOnMainThread:...] which then calls a delegate method. I understand that I need to nil the delegate reference before releasing the delegate, but I was wondering what happens if this requesting object itself gets deallocated while the background thread is running. Will this internal self reference get set to nil so that the -performSelectorOnMainThread: call is harmless, or is there a potential for a crash here?
As far as I understand your scenario (but possibly you should include some code), the statement:
[self performSelectorOnMainThread:...]
should be the last one to be executed in your thread (since it is the way to return the result of your thread, it is still part of the thread selector passed to NSThread).
If it is reasonably so, then consider that when you first detach an NSThread, you pass it a target object (your self) and the NSThread will retain it as long as the passed selector hasn't completed. This will include your [self performSelectorOnMainThread:...], so, unless someone messes heavily with releases, there should be no chance for self to be deallocated before [self performSelectorOnMainThread:...] is executed.
If your question was exactly what happens if someone messes with releases, I will give this a second thought.
If your object is deallocated before the method on the main thread completes, you have a memory management problem. The performSelectorOnMainThread:… family of methods cause the receiver to be retained until it has done its work, so the only way it could be deallocated is if you're over-releasing the object.

does dealloc method being executed normally when quitting the application?

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?