Освобождать локальные переменные перед возвратом?

Я понимаю, что в target-c вам нужно выпустить все, что вы инициализируете/сохраняете/копируете. Нужно ли мне делать это перед оператором return? Я хочу понять явный вызов release и не использовать autorelease.

-(void) someMethod
{
  AnotherClass* ac = [[AnotherClass alloc] init];
  if([ac somethingHappens]){
    // Do I need to release ac here?
    return;
  }
  [ac doSomethingElse];
  [ac release];
}

Спасибо!


person Sam Washburn    schedule 17.02.2010    source источник
comment
это плохая практика - иметь несколько маршрутов возврата, которые у вас есть в приведенном выше коде, один явный и один неявный. вы должны переместить возврат ниже [выпуска], представьте себе множество операторов if(), каждый из которых выполняет возврат, это много повторяющегося кода.   -  person    schedule 18.02.2010
comment
Почему это плохая практика, потому что ей трудно следовать? Похоже, что следование множеству логик может быть столь же сложным.   -  person Sam Washburn    schedule 18.02.2010
comment
это невозможно поддерживать, когда у вас есть 30 мест, которые вы должны скопировать и вставить блок кода выпуска, и когда вы добавляете еще одну вещь, которую нужно иметь [выпуск], вам теперь нужно обновить 30 мест. Это нарушает принцип DRY (не повторяйтесь). Лучшей практикой, если у вас есть возвращаемое значение, является установка возвращаемого значения в логике, а затем возврат этого значения в нижней части функции, сразу после вашей единственной точки блоков [release].   -  person    schedule 18.02.2010


Ответы (2)


Да, вам нужно освободить свои переменные, однако вы выходите из метода.

Это довольно просто: когда вы запускаете что-то, количество сохранений увеличивается. Когда вы отпускаете, он уменьшается. Когда он достигает нуля, он автоматически освобождается (освобождается).

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

person Stephen Darlington    schedule 17.02.2010
comment
На самом деле, это не когда вы init что-то, а когда вы alloc что-то. Если ваш метод init не вызывает [super init], счетчик сохранения по-прежнему равен 1. - person dreamlax; 17.02.2010
comment
@Стивен, спасибо, это то, что мне нужно было знать. Я тоже теперь это лучше понимаю. - person Sam Washburn; 17.02.2010
comment
@Sam Washburn: Вы были правы до того, как отредактировали свой вопрос. В документации для метода alloc NSObject явно указано, что он сохраняет объект перед его возвратом. - person dreamlax; 17.02.2010

Предположим, что локальная переменная назначена следующим образом

NSString *placeHolder = [NSString stringWithFormat:@"%@ %@",[someObject value1], [someObject value2]];

Теперь передайте эту переменную методу, определенному объектом, например, setPlaceholder объекта UISearchBar.

[self.theSearchBar setPlaceholder:placeHolder];

Как правильно освободить назначенную строку «placeHolder»?

Если вы предполагаете его авторелиз:

NSString *placeHolder = [[NSString stringWithFormat:@"%@ %@",[someObject value1], [someObject value2]] autorelease];

ваш код потерпит неудачу с bad_exc_access

Если вы думаете выпустить переменную после передачи в другое место, например

[self.theSearchBar setPlaceholder:placeHolder];
[placeHolder release];

исключение времени выполнения тоже будет брошено.

Так что же не так?

Проблема заключается в сохранении счетчика. Объект UISearchBar еще выделен, поэтому, если вы освобождаете или автоматически освобождаете такую ​​переменную, на которую ссылается этот объект, счетчик сохранения остается прежним.

NSLog(@"Retain count before assign to refer other object %d", [placeHolder retainCount]);
[self.theSearchBar setPlaceholder:placeHolder];
NSLog(@"Retain count after referencing %d", [placeHolder retainCount]);

Итак, как справиться с этим?

Попробуйте что-то вроде следующего

[placeHolder retain]; // retainCount +1
[self.theSearchBar setPlaceholder:placeHolder];
[placeHolder release]; // retainCount -1

Чем мы занимались? Давайте теперь посмотрим на количество удержаний

NSLog(@"Retain count before doing retain %d", [placeHolder retainCount]);
[placeHolder retain]; // retainCount +1
NSLog(@"Retain count after retaining it %d", [placeHolder retainCount]);

Итак, мы увеличили счетчик сохранения, прежде чем присвоить его (получить ссылку) какому-либо объекту, а после этого мы локально освобождаем эту переменную.

Это все.

person loretoparisi    schedule 22.07.2011