开发者

Is returning nil from a [[class alloc] init] considered good practice?

开发者 https://www.devze.com 2023-01-11 13:24 出处:网络
And is it a common idiom in Objective-C. I\'ve only seen this used on [[NSImage alloc] initWithConten开发者_如何学JAVAtsOfFile: str] and it always make me think there is a memory leak, because i call

And is it a common idiom in Objective-C.

I've only seen this used on [[NSImage alloc] initWithConten开发者_如何学JAVAtsOfFile: str] and it always make me think there is a memory leak, because i called alloc and the mantra is: "Call alloc and you must call release" - unless its one of the cases where you don't need to.


It is a common idiom to indicate a error in initializing the object. You are correct, however, the allocated instance must be released. So the pattern would be

- (id)init
{
  self = [super init];
  if(self != nil) {
    //... do init
    if(errorInInit) {
      [self release];
      return nil;
    }
  }

  return self;
}


See using alloc and init for more issues and answers regarding init methods.

An init method that also accepts args (ex: initWithXxx:(Xxx*)x such as NSString's initWithBytes:) could return nil without ever calling [super init] if (for example) it did not like an arg it received. An init method must manage memory just like any method. It's just that init has the somewhat unusual behavior of returning its self or returning some other object, as it chooses. Not much call for that in general.


Two follow-up questions to this topic that I haven't seen definitive answers to - now repeated in its own question, Followup to returning nil from a [[class alloc] init]

1: What to do with an init that fails some preconditions before it can call super. Example, suppose in this initWithStuff: method being passed nil or in general having no value to pass to initWithValue: is an absolute failure and we definitely want to return nil.

- (id)initWithStuff:(Stuff *)inStuff {
  if (!inStuff || ![inStuff hasValidValue])
  {
    // can't proceed to call initWithValue: because we have no value
    // so do what?
    return nil;
  }
  NSInteger value = [inStuff integerValue];
  return [super initWithValue:value];
}

Perhaps a clearer example is if the designated initializer method we wrap takes an object pointer and throws an exception if its passed nil. We definitely need to short-circuit that init call that would cause an exception.

My guess: init by any means possible, and only then release self before returning nil. If necessary, call bare init or any other initializer that will work to finish putting self into a known state before releasing it.

  // can't proceed to call super's initWithValue: because we have no value
  // so do what? do this:
  self = [super init]; // or initWithValue:0
  [self release];
  return nil;

And if there were no such initializer that will work without valid data, I guess one would need to construct some valid, dummy data. Or complain to its author and until then just return nil and live with the leak :^)

2: How does ARC affect the situation?

My guess: still finish init by any means possible, then just return nil. You'd think setting self might be redundant, but in some cases it's not. In any case, it but it needs to be there to silence a compiler warning.

  // can't proceed to call super's initWithValue: because we have no value
  // so do what? do this:
  self = [super init]; // finish init so ARC can release it having no strong references
  return nil;
0

精彩评论

暂无评论...
验证码 换一张
取 消