Считается ли возвращение nil из [[class alloc] init] хорошей практикой? - PullRequest
2 голосов
/ 12 августа 2010

И это распространенная идиома в Objective-C.

Я видел только то, что использовалось в [[NSImage alloc] initWithContentsOfFile: str], и это всегда заставляет меня думать, что есть утечка памяти, потому что я вызвал alloc, и мантра: «Позвоните на выделение, и вы должны позвонить на освобождение» - если только это не один из случаев, когда вам не нужно.

Ответы [ 3 ]

6 голосов
/ 12 августа 2010

Распространенная идиома, указывающая на ошибку при инициализации объекта. Вы правы, однако выделенный экземпляр должен быть освобожден. Таким образом, шаблон будет

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

  return self;
}
0 голосов
/ 08 ноября 2012

Два последующих вопроса к этой теме, на которые я не видел однозначных ответов - теперь повторяется в своем собственном вопросе Продолжение возврата nil из [[class alloc] init]

1: Что делать с init, который не выполняет некоторые предварительные условия, прежде чем он сможет вызвать super. Пример, предположим, что в этом initWithStuff: метод передан nil или вообще не имеет значения для передачи initWithValue: это абсолютный сбой, и мы определенно хотим вернуть 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];
}

Возможно, более ясный пример, если назначенный нами метод инициализатора, который мы переносим, ​​берет указатель на объект и выдает исключение, если ему передано значение nil. Нам определенно нужно замкнуть этот вызов init, который вызовет исключение.

Мое предположение: init любыми возможными способами, и только потом освободить себя, прежде чем вернуть nil. При необходимости вызовите bare init или любой другой инициализатор, который будет работать, чтобы завершить перевод себя в известное состояние перед его освобождением.

  // 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;

И если бы не было такого инициализатора, который работал бы без допустимых данных, я думаю, что нужно было бы построить некоторые допустимые, фиктивные данные. Или пожаловаться его автору и до этого просто вернуть ноль и жить с утечкой: ^)

2: Как ARC влияет на ситуацию?

Мое предположение: все равно завершите init любым доступным способом, затем просто верните ноль. Вы могли бы подумать, что установка self может быть излишней, но в некоторых случаях это не так. В любом случае, но он должен быть там, чтобы отключить предупреждение компилятора.

  // 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 голосов
/ 10 января 2012

См. с использованием alloc и init для получения дополнительных вопросов и ответов, касающихся методов init.

Метод init, который также принимает аргументы (например: initWithXxx:(Xxx*)x, например NSString 's initWithBytes:) может вернуть nil, даже не позвонив [super init], если (например) ему не понравится полученный аргумент.Метод init должен управлять памятью, как любой метод.Просто у init есть несколько необычное поведение - возвращать self или возвращать какой-то другой объект по своему выбору.В общем, не так уж и много.

...