overriding the dealloc method in objective-c - 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.

Related

On comma separated expressions in Objective-C

I recently came across this blog post where two flavors of instance variable deallocation are discussed. To give you a summary:
The first approach
- (void)dealloc {
[instanceVar release];
[super dealloc];
}
is considered to leave a pointer alive until the method returns. This can lead to undefined behavior.
The second approach
- (void)dealloc {
[instanceVar release], instanceVar = nil;
[super dealloc];
}
is considered to be more stable for production code because the instaceVar is set to nil.
OK. Here is the question you've been waiting for:
Are both solutions the same? Or does the comma separation of expressions make them atomic?
The blog post you link to is from 2010.
The more interesting point nowadays is that you have to do neither. If you use ARC, then you can't send a release message to objects.
The setting of nil after release was to prevent non-retained objects to be sent messages after they were deallocated and cause a crash. I say non-retained objects, because if they were retained objects, they wouldn't (shouldn't) be released unknowingly. Again, with ARC (as long as you aren't using ARC-lite) you can mark non-retained objects as weak, and weak pointers auto-zero; i.e. when the object they point to is deallocated, the pointer is set to nil.
So the second case, with pointers being set to nil after a dealloc, is considered safer at run-time, but you don't have to worry about it now, as ARC handles that for you.
The comma doesn't make it atomic, but there should only be one thread invoking dealloc anyway or else you have much, much larger problems on your hands. Setting instanceVar to nil is unnecessary, it isn't safer, because if there is a bug in your program that somehow uses the dangling value in instanceVar it will only manifest differently depending on whether it is nil or something else, either way, there is a bug, because nothing should be relying on that value.
With ARC this is even less of an issue. A dealloc method in ARC is only used to release non-ARC-controlled resources, everything else is automatically handled for you.

Override "release" or "dealloc"

Which is the best method
Override "release" or "dealloc" method in objective c?
why?
Under non-ARC, 99% of the cases you should not override the release method.
I have seen only 1 case that the need to override the release method - a kind of singleton, which forces the class have really 1 single instance no matter how many times you call alloc.
That way override not only the release method, but also allowWithZone:, retain, 'retainCount`, etc. (It is actually not common to implement that kind of singleton)
Which is the best method? Override the release or the dealloc method?
- dealloc, definitely. You should never override - release.
Why?
One, because release does a bunch of internal stuff. Two, because if release is called, it does not mean that the object is deallocated.
So you would release your ivars or null your properties by accident. And who wants an ugly segfault when we can have worldpeace instead?
If an object is really deallocated, - dealloc will be called.
If you are not using ARC, you should override the -[MyObject dealloc] dealloc method to release all retained objects inside your object. I have never found a case where I needed to override the release method.
If you are using ARC, you can usually avoid overriding the -dealloc method at all, unless you are using anything that ARC won't free up like a sqlite pointer or something.
dont override either for anything not relating to memory management - you dont when and if those methods even get called.
exceptions for when you should dealloc:
removing KVO / notification center observer
deallocating manually allocated memory (arc) / release your ivars (non-arc)

Why can I release an ivar after [super dealloc] without segfaulting?

It seems that in Objective-C, the method that is responsibile for memory allocation (like malloc() in C), is -[NSObject alloc]. What about freeing that memory? Is that done by -[NSObject dealloc]? Is that why in our own class's dealloc, we must call [super dealloc] last, instead of first?
I ask because I don't understand why, if I put [super dealloc] first, and release an object using [_bar release] on the next line, I don't get a segmentation fault. After [super dealloc] runs, if it frees the object's memory, _bar should already be a memory chunk that doesn't belong to the process.
I think you are saying, you have this code:
- (void)dealloc
{
[super dealloc];
[_bar release]; // _bar is a member variable
}
And you expect to get a segmentation fault on the second line, but in practice you are not.
The reason for this is luck!
The OS will trap access to memory that your process does not own, but it doesn't police everything that happens inside your process. In this case, you are accessing memory that you have marked as free, but it still belongs to your process, and so behavior is undefined. The memory was valid a few milliseconds ago, and so it is likely that nobody has started reusing this page of memory yet, and so it probably still has valid data on it. So it might succeed. But it also might fail.
This is bad code and you shouldn't ship it. But just because it is incorrect and undefined doesn't mean it won't work.
-dealloc ultimately frees the memory associated with an Objective-C object (presumably through free(), but that's an implementation detail.) The only reason you are able to send a message after -dealloc is because of undefined behaviour. After [super dealloc] is sent, any further messages to self or its ivars is unsafe.
In the simplest "conceptual" case, the dealloc routine for NSObject does the free operation, mirroring the malloc done in the alloc routine. In practice it may be different, but that's all smoke and mirrors, so long as the conceptual model is satisfied.
If you put [super dealloc] first in your (pre-ARC) dealloc routine it mostly doesn't seg fault because the space, while freed, has not had time to be overwritten by some other object (and it doesn't physically go away when deallocated -- it just goes into an "available" list).
Yes, alloc is where the allocation is done. Note that it may or may not be done, sometimes there's no allocation at all (this is an implementation detail). The allocation generally happens in the NSObject implementation of alloc.
If memory was allocated, then the chained call to dealloc is the one that eventually releases it.
You are not supposed to access instance variables after calling [super dealloc]. This does not mean that if you do you get a segfault. You may or may not segfault, it's undefined behavior.
An important thing to remember, however, is that you should never call dealloc directly, except for the call to [super dealloc] in the dealloc implementation itself. Objective C is reference counted. When you are done with an object you do not dealloc it. Instead you release it (or autorelease it if you are done but you are returning it to the caller and have no idea if the caller will use it or not). The actual call to dealloc happens automatically when the system is sure that nobody is going to reference that object any more.
Edit:
I shall clarify sometimes there's no allocation at all. In fact the allocation generally happen if you call alloc, but the init* methods may undo it. As a rule all calls to alloc should immediately be followed by a call to one of the initializers. The initializers, however, do not need to initialize the self they receive. They could instead get rid of it (therefore freeing the memory) and return a completely different object, which may or may not be allocated.
Therefore, in that case, the memory allocated by alloc is in fact released by the initializer (may or may not call dealloc to do that). ANd the object that you get after initialization may be a static object that is not allocated on the heap and will never be freed. It could also be a non pointer (an invalid address) that is cast to (void*) (aka id) and returned.

Should -dealloc do anything other than release memory?

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.

Objective-C Delegate Pointers

If we write the following code:
ExplorerAppDelegate * appDelegate = (ExplorerAppDelegate *)[[UIApplication sharedApplication] delegate];
This makes a reference to the original delegate pointer, but:
Does it increase the reference count?
Do we have to explicitly call as [ExplorerAppDelegate retain] right after, or not at all?
What's happening, exactly?
After we've used this, we should also do a [ExplorerAppDelegate release] in the dealloc method, right?
No, it does not increase the retain count.
The convention in Objective-C is that objects you are given should be memory managed by yourself - but in the case of obtaining a shared common resource like the app delegate, the memory is maintained elsewhere and of course (with this being the app delegate) you know that it will always be "alive" as long as your class is... so there is no need to retain the reference.
In most uses of delegates, instead of fetching a delegate you are given one, and that reference is not retained either. In that case whoever gave you the delegate is also responsive for clearing out the delegate link before the delegate is released.
The reason you don't want to generally retain delegate references is that it can prevent some objects from being deallocated, for instance if one class is a delegate of a class that ues the other class as a delegate.
The reference count will not be increased
You should retain it if you want to be sure that it isn't deallocated while you have a pointer to it
You should only release it if you retained it
So basically, if you're only using the object in a single function, you probably don't need retain or release it. If it exists when you get it, then it's (probably) not going to be deallocated by the end of the function. If you're keeping it around, in an ivar (member variable) for example, then you should retain it and release it later.
See the "Weak References to Objects" in Memory Management Programming Guide for Cocoa for the official answer. Pointers to delegates are one of the possible exception cases to the memory management rules.