« No Hacking / SPAM | Main | Harvested some more SPAMers »

Why NSNotifications during dealloc are a recipe for desaster

There was a Mulle internal discussion a year back about the use of dealloc notifications in some framework. Here is a little demo code that shows, that dealloc notifications - or notifications during dealloc in general - are not a good idea.
#import <Foundation/Foundation.h>
#import <Foundation/NSDebug.h>

@interface Problem : NSObject
{
}
@end


@implementation Problem

- (void) dealloc
{
   NSNotification  *notification;

   notification = [NSNotification notificationWithName:@"AsIDie"
                                                object:self];
   // it's synchronous... yet...
   [[NSNotificationCenter defaultCenter] postNotification:notification];
   [super dealloc];
}

@end


int main (int argc, const char *argv[])
{
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

   NSZombieEnabled = YES;
   [[[Problem alloc] init] release];
   [pool release];
   return( 0);  
}
This is the output:

2003-09-13 14:50:36.772 DeallocNotification[1679] *** *** Selector 'release' sent to dealloced instance 0x54450 of class Problem.
Break at '-[_NSZombie release]' to debug.
2003-09-13 14:50:36.784 DeallocNotification[1679] *** -[NSAutoreleasePool dealloc]: Exception ignored while releasing an object in an autorelease pool: NSGenericException *** Selector 'release' sent to dealloced instance 0x54450 of class Problem.
Break at '-[_NSZombie release]' to debug.

The problem is that NSNotification retains and subsequently autoreleases the object. The object is retained while in the process of deallocation. release and dealloc will be now called one more time from the NSAutoreleasePool, when it dies. But the deallocation can't be stopped now. This will lead to - possibly quite subtle - crashes.

Bottomline, keep the dealloc routine as stupid as possible to save yourself some trouble.

Comments (2)

znek:

And yet there are cases where you don't have a chance to prevent sending notifications during dealloc. XRConnection's dealloc comes to mind, where you *have* to post an XRConnectionDidDieNotification. Interestingly, GNUstep (gnustep-base) now has a working solution for the problem mentioned above. Now guess what solved as a test case for this solution? ;-)

Nat!:

It would probably be better to overwrite -release like this:

- (void) release
{
if( [self retainCount] == 1)
{
//notify about to die
}
[super release];
}

The only problem is that the notification maybe sent to early or there may be duplicates, if someone doesn't cooperate.

About

This page contains a single entry from the blog posted on September 15, 2003 2:30 AM.

The previous post in this blog was No Hacking / SPAM.

The next post in this blog is Harvested some more SPAMers.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.34