Three ways to dealloc
1. Just release
- (void)dealloc {
[airplane release];
[super dealloc];
}
Now the object reference points to a random position, which may be one of two things:
- Most likely it is garbage, because the memory position can't be interpreted as an object.
- Rarely it will be a different object, because memory have been reused to create a new object.
The effect of a further method calls through this pointer is one of these three (which one is undefined):
- A crash with
EXC_BAD_ACCESS
because the pointer points to garbage.
- A crash with undefined selector because it points to a valid object which doesn't have that method.
- A successful method execution because the new object has a method by the same name.
2. Release and nil
- (void)dealloc {
[airplane release], airplane = nil;
[super dealloc];
}
Now the object reference is nil and any further method calls are ignored. This may silently cause a defined but unforeseen lateral effect in your code, but at least it doesn't crash your application.
3. Nil and release
- (void)dealloc {
id temp = airplane;
airplane = nil;
[temp release];
[super dealloc];
}
This is the same as before, but it removes that small window between release and nil where the object reference points to an invalid object.
Which one is best?
It is a matter of choice:
- If you rather crash choose just release.
- If you rather ignore the mistake choose nil+release or release+nil.
- If you are using
NSZombieEnabled=TRUE
then just release, don't nil the zombie!
Macros and zombies
A easy way to defer your choice is using a macro. Instead [airplane release]
you write safeRelease(x)
where safeRelease is the following macro that you add to your .pch target file:
#ifdef DEBUG
#define safeRelease(x) [x release]
#else
#define safeRelease(x) [x release], x=nil
#endif
This macro doesn't respect zombies. Here is the problem: when NSZombieEnabled
is TRUE
the object turns into a NSZombie
. If you nil its object reference, any call sent to him will be ignored.
To fix that, here is a macro from Kevin Ballard that sets the pointer to an invalid made up reference ONLY when NSZombieEnabled
is FALSE
. This guarantees a crash during debug time if zombies are not enabled, but leaves the zombies be otherwise.
#if DEBUG
#define safeRelease(x) do { [x release]; if (!getenv("NSZombieEnabled")) x = (id)0xDEADBEEF; } while (0)
#else
#define safeRelease(x) [x release], x = nil
#endif
References
Apple doesn't have a recommendation on which one is best. If you want to read the thoughts of the community here are some links (the comment threads are great too):
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…