Ненужные временные переменные при установке значений свойств? - PullRequest
3 голосов
/ 11 октября 2009

Я слежу за книгой по разработке для iPhone, и в коде примера я постоянно наблюдаю определенный паттерн, который не имеет для меня особого смысла. Всякий раз, когда свойство устанавливается, они сначала назначают указатель на новое значение для свойства, затем устанавливают свойство на указатель, а затем освобождают указатель. Пример:

Интерфейс:

@interface DoubleComponentPickerViewController : UIViewController {
    NSArray *breadTypes;
}

@property(nonatomic, retain) NSArray *breadTypes;

@end

Метод класса:

- (void)viewDidLoad {
    NSArray *breadArray = [[NSArray alloc] initWithObjects:@"White", @"Whole Wheat", @"Rye", @"Sourdough", @"Seven Grain", nil];
    self.breadTypes = breadArray;
    [breadArray release];
}

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

- (void)viewDidLoad {
    self.breadTypes = [[NSArray alloc] initWithObjects:@"White", @"Whole Wheat", @"Rye", @"Sourdough", @"Seven Grain", nil];
}

Спасибо за свет, который без сомнения будет пролито:)

Ответы [ 2 ]

9 голосов
/ 11 октября 2009

Позвольте мне попытаться объяснить это по-другому.

Метод, имеющий в своем имени alloc, copy или new, выделяет память для объекта и передает право собственности на этот объект вызывающей стороне, и вызывающая сторона несет ответственность за освобождение этой памяти.

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

Независимо от того, что вы хотите с ним делать, вы должны разблокировать его (или автоматически выпустить *). В этом случае вы используете объект для передачи его в self.breadTypes. self.breadTypes может не выглядеть как метод, но это так (это сеттер). Вы передаете это breadArray. Он делает то, что нужно с ним. Он может сохранить его для последующего использования или скопировать из него некоторую информацию или сделать копию всего этого. Ваш viewDidLoad на самом деле не волнует. Предполагается, что self.breadTypes делает то, что ему нужно, и когда он возвращается, ему все равно, что вы делаете с breadArray.

И что вы делаете с этим, это то, что вы должны делать со всем, что у вас есть - отпустить (или автоматически выпустить * это).

Вот почему вы должны использовать переменную temp, breadArray. Вы не можете полностью освободить результаты от alloc в той же строке, так как объект будет освобожден раньше, чем self.breadTypes может иметь в нем:

self.breadTypes = [[[NSArray alloc] initWithObjects:@"White", ..., nil] release];

Таким образом, вы вынуждены присвоить временную переменную, передать ее в self.breadTypes, а затем освободить объект, сохраненный в breadArray.

Теперь вы можете попытаться сделать это таким образом, чтобы не использовать временную переменную:

- (void)viewDidLoad {
    self.breadTypes = [[NSArray alloc] initWithObjects:@"White", @..., nil];
    [self.breadTypes release];
}

но это не очень эффективно, так как вы вызываете еще один метод (self.breadTypes как метод получения), который вам действительно не нужен, если вы только что сохранили значение во временной переменной.

* Теперь, как сказал респондент, вы можете использовать авто-релиз для альтернативной версии:

- (void)viewDidLoad {
    self.breadTypes = [[[NSArray alloc] initWithObjects:@"White", ..., nil] 
                        autorelease];
}

Apple призывает нас дважды подумать о том, хотим ли мы использовать авто-релиз против релиза. Авто-релиз не может быть лучшим выбором для любой ситуации. Мне лично нравится убирать за собой как можно скорее, и я не использую авто-релиз без необходимости. Автоматически освобожденные объекты освобождаются в конце выполнения цикла выполнения, например, вскоре после возвращения viewDidLoad. Вы должны прочитать немного больше об авто-выпуске (и об управлении памятью на iPhone, который немного отличается от MacOS X Cocoa), поскольку я упрощаю все это.

Кстати: если вы retain объект, вы принимаете на себя владение им, и вы будете нести ту же ответственность снова, release после того, как вы закончите с ним.

3 голосов
/ 11 октября 2009

Да. Эти методы распределяют переменные, поэтому они должны быть освобождены. Тот факт, что свойство имеет атрибут retain, означает, что когда вы говорите @synthesize breadTypes;, компилятор фактически генерирует setBreadTypes, который должным образом освобождает текущий элемент breadType и сохраняет новый. Таким образом, ваша функция не должна сохранять переменную it alloc 'ed.

Вы могли бы, однако, написать:

- (void)viewDidLoad {
    self.breadTypes = [[[NSArray alloc] initWithObjects:@"White",
                              @"Whole Wheat", @"Rye", @"Sourdough",
                              @"Seven Grain", nil] 
                        autorelease];
}

Вы хотите освежить в памяти Управление памятью какао

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...