#iphone #objective-c #cocoa-touch #memory-management
#iPhone #objective-c #cocoa-touch #управление памятью
Вопрос:
В моей книге по разработке iPhone я вижу несколько странных примеров кодирования в отношении того, что делает массив, когда объекты добавляются в массив и когда весь массив освобождается. Один пример кода имеет следующие свойства для массива экземпляров:
@property (nonatomic, retain) NSMutableArray* myArray;
Автор добавляет объект в массив и сразу после этого освобождает свой указатель на объект. Не будет ли ячейка массива теперь указывать на данные мусора? Если только за кулисами ячейка массива не сохраняет объект при добавлении.
SomeObject* someObject = [[SomeObject alloc] init];
[self.myArray addObject:someObject];
[someObject release];
Автор также освобождает указатель на массив, не просматривая сначала каждую ячейку массива и не освобождая отдельные объекты. Это утечка памяти, если только за кулисами каждой ячейке не будет отправлено сообщение о освобождении;.
- (void)viewDidUnload {
self.myArray = nil;
[super viewDidUnload];
}
Комментарии:
1. Оба ваших ‘если’ на самом деле таковы, как они работают. AddObject в NSMutableArray сохраняет объект, и все сохраненные объекты освобождаются при освобождении массива.
2. Это потому, что массив обладает
retain
свойством или все NSMutableArray демонстрируют такое поведение? Где документация по этому поводу?3. Пожалуйста, посмотрите мой ответ на концепцию «вам нужно сохранить то, что вы хотите использовать последним» 🙂
Ответ №1:
Если только за кулисами ячейка массива не сохраняет объект при добавлении.
Да, это происходит.
… если только за кулисами каждой ячейке не отправляется сообщение об освобождении.
Это тоже случается.
Вы сами ответили на свой вопрос.
Вот цитата из Collections Programming Topics:
И когда вы добавляете объект в объект NSMutableArray, объект не копируется (если вы не передадите YES в качестве аргумента initWithArray:copyItems:). Скорее, объект добавляется непосредственно в массив. В среде управляемой памяти объект получает сообщение о сохранении при его добавлении; в среде сбора мусора на него строго ссылаются. Когда массив освобождается в среде управляемой памяти, каждому элементу отправляется сообщение об освобождении.
Ответ №2:
В отличие от C или C , где вы постоянно беспокоитесь о том, удалять объект или нет, опасаясь, что он все еще используется где-то еще, Objective-C (или, скорее, это фактически Cocoa SDK) использует механизм подсчета ссылок или владения.
Возможно, вы уже знаете, как это работает, но вам также нужно знать, что в Cocoa, если объекту A необходимо использовать другой объект B, он должен владеть им (т. Е. сохранять). Этот объект A не должен полагаться на какой-либо другой объект C, уже сохраненный B, потому что он не может знать, когда C его освобождает. Итак, в вашем случае, поскольку NSArray необходимо использовать все объекты, добавленные к нему позже в течение срока его службы, ему необходимо сохранить все объекты. И из-за этого, когда массив отменяется, ему необходимо освободить их.
Концепция «вам нужно сохранить то, что вы хотите использовать последним» очень важна, когда вы имеете дело с большим количеством объектов.
Ответ №3:
В руководствах Apple по разработке есть несколько мест, в которых объясняется, что хорошей практикой является передача права собственности на объект (отправка сообщения о сохранении), если вы планируете использовать его позже. Вы должны сделать это так, чтобы объект не был уничтожен, пока вам все еще может понадобиться доступ к нему.
Учитывая это, вы были правы, предположив, что NSArray сохраняет объект при его добавлении в коллекцию, поскольку он все равно может попытаться получить к нему доступ впоследствии.
Вы можете ознакомиться с руководством по программированию управления памятью
Когда вы добавляете объект в коллекцию, такую как массив, словарь или набор, коллекция становится его владельцем.
или в разделах по программированию коллекций для получения более подробной информации
… В среде управляемой памяти объект получает сообщение о сохранении при его добавлении.
Ответ №4:
-
Вы правы в первом пункте. Когда объект добавляется в массив, массив сохраняет объект. Таким образом, для объекта, который был ранее сохранен, необходимо освободить его после добавления в массив, иначе может возникнуть утечка памяти.
-
Аналогично, когда объект удаляется из массива, массив освобождает объект. Итак, если вы хотите сохранить это, вам нужно это сохранить.
-
Когда массив освобождается, как вы и предполагали, массив освобождает все содержащиеся в нем объекты. Таким образом, освобождение каждого объекта по отдельности не является необходимым и, фактически, вызвало бы исключение.
-
Наконец, что касается строки кода в viewDidUnload, которую вы процитировали:
self.myArray = nil;
Это работает должным образом в отношении управления памятью, если свойство myArray было синтезировано следующим образом:
@synthesize myArray;
При синтезе создается сеттер, который эффективно выполняет следующее:
- (void)setMyArray(NSMutableArray *)anArray
{
if (![myArray isEqual:anArray]) {
[myArray release];
myArray = anArray;
[myArray retain];
}
}
Итак, при вызове вышеуказанный установщик сначала освободит старый массив (при условии, что это не тот же объект, что и новый массив.) Затем он сохранит новый массив, который в данном случае равен нулю. Обратите внимание, что сохранение nil просто ничего не сделает и не вызовет ошибку.
Конечно, если вы не синтезируете свойство myArray или переопределяете параметр setter, у вас возникнут проблемы с памятью, если вы также не освободите старое значение и не сохраните новое в своем параметре setter.