views:

85

answers:

1

Should I always release self when there is a failure inside init, or should I only do so if I have initialized instance variables first?

To put it another way, is this pattern valid? Is there a time when I shouldn't release self inside an init method, or should I assume that if the control flow enters init, self has at least a retain count of 1?

- (id)init
{
 if ((self = [super init]) == nil)
 {
  [self release];
  return nil;
 }

 //do some init stuff
 if (somethingFailed)
 {
  [self release];
  return nil;
 }
 return self;
}
+7  A: 

If some check you need in your initialization method fails, then yes you should release self. Note however, that if [super init] returns nil it does not make sense to send release to self as self is nil. This is actually frown on by Apple

You should only call [self release] at the point of failure. If you get nil back from an invocation of the superclass’s initializer, you should not also call release.

Example

- (id)init
{
   self = [super init];
   if(self) {
       // do some init stuff

       if (somethingFailed)
       {
          [self release]
          self = nil;
       }
   }

   return self;
}

Also see the Mac Dev Center documentation on Handling Initialization Failure

Brandon Bodnár
Ah, seems so obvious now that you point it out. I was a little thrown off because I am invoking release on an object that I did not invoke alloc/copy/new etc on.
leo
Yeah, the basic principle is that whoever first encounters an error in initialization should release the allocated space that init is being called on, and then should return nil. Since everyone else gets nil, they have no way of releasing the memory, hence why you should call release on self so to avoid a memory leak.
Brandon Bodnár
Makes sense, thanks.
leo
Odd that the documentation would specifically tell you not to send a message to nil, since nothing should happen.
tedge
@tedge I thought the same thing, since sending release to nil is well defined as a no-op.
Brandon Bodnár