Указатели Objective-C / вопрос управления памятью - PullRequest
1 голос
/ 29 июля 2011

Я тестирую следующий код ниже. ffv объявлен в файле интерфейса.

ffv = [[FullFunctionView alloc] initWithFrame:self.view.bounds];
NSLog(@"%i", [ffv retainCount]);  // prints 1
[self.view insertSubview:ffv belowSubview:switchViewsBtn];
NSLog(@"%i", [ffv retainCount]);  // prints 2
[ffv release]; // you can release it now since the view has ownership of ffv
NSLog(@"%i", [ffv retainCount]);  // prints 1

if (ffv == nil)
    NSLog(@"ffv is nil");

// "ffv is nil" is not printed

[ffv testMethod]; // "test method called" is printed

это моя реализация [ffv testMethod]

- (void)testMethod
{
    NSLog(@"test method called");
}

В этом случае я могу сделать вывод, что даже если вы отпустите объект с сохранением счетчика 2, вы потеряете право собственности на этот объект, однако ссылка все равно останется.

Теперь мой вопрос:

  1. Правильно ли сделан мой вывод?
  2. Есть ли что-нибудь еще важное, что можно из этого сделать?
  3. Каковы сложности, вызванные сохранением (использованием) ffv и вызовом методов из ffv? (Мое мнение таково, что это нормально, поскольку представление всегда будет иметь ffv и не освободит его, пока кто-то не вызовет viewDidUnload. И до тех пор, пока я не передам ссылку ffv на другие объекты.)

Ответы [ 5 ]

2 голосов
/ 29 июля 2011

Есть несколько проблем с использованием ffv после того, как вы выпустили его, и он сохраняется только в представлении вашего контроллера представления.

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

2) В особом случае UIViewController представление может быть освобожденов любое время (обычно вы никогда не звоните viewDidUnload самостоятельно).Поведение по умолчанию UIViewController при получении предупреждения о памяти, и представление в настоящее время невидимо, состоит в том, чтобы освободить представление, поэтому, если вы не установите ссылку на nil в viewDidUnload, у вас снова будет свисающий указатель, даже если выникогда не выдавал свое мнение явно.

0 голосов
/ 29 июля 2011

1) Мой вывод правильный?

Ваш вывод правильный. Руководство по программированию управления памятью объясняет, что у каждого объекта есть один или несколько владельцев.Вы владеете любым созданным вами объектом, используя любой метод, начинающийся с alloc, new, copy или mutableCopy.Вы также можете вступить во владение объектом используя retain.Когда вы закончите работу с объектом, вы должны отказаться от владения, используя release или autorelease.

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

2) Есть ли что-то еще важное, что можно из этого извлечь?

Ничего не приходит на ум.

3) Каковы сложности, вызванные сохранением (использованием) ffv и вызовом методов из ffv?(Мое мнение таково, что это нормально, поскольку представление всегда будет иметь ffv и не освободит его, пока кто-то не вызовет viewDidUnload. И до тех пор, пока я не передам ссылку ffv на другие объекты.)

Когда вы звоните release, вы сообщаете среде выполнения Objective C, что вам больше не требуется доступ к объекту.Хотя может быть много случаев, подобных этому, в которых вы знаете, что объект все еще будет существовать, на практике вы действительно не должны обращаться к объекту после вызова release.Вы бы просто искушали судьбу и настраивали себя на будущие ошибки.

Лично мне не нравится перетекать свой код заявлениями release, потому что я не доверяю себе, чтобы запомнить их на 100%время.Вместо этого я предпочитаю автоматически высвобождать мои переменные, как только я распределю их следующим образом:

ffv = [[[FullFunctionView alloc] initWithFrame:self.view.bounds] autorelease];

Это гарантирует, что ffv будет существовать по крайней мере до конца метода.Он будет выпущен вскоре после этого, обычно перед следующей итерацией цикла выполнения.(Теоретически это может занять слишком много памяти, если вы размещаете большое количество временных объектов в узком цикле, но на практике я никогда не сталкивался с этим случаем. Если я когда-либо это сделаю, его будет легко оптимизировать.)

0 голосов
/ 29 июля 2011
if (ffv == nil)
    NSLog(@"ffv is nil");
// "ffv is nil" is not printed

Это верно, освобождение объекта не устанавливает указатель на nil , даже если он был освобожден в это время . Хорошая практика - всегда устанавливать указатель на ноль после того, как вы отпустите его. Вы правы сказать, что после того, как вы выпустили его, он не был отменен, потому что представление все еще сохранялось. Но это не то, как вы должны думать об этом. Если вы хотите использовать этот объект и хотите, чтобы он был живым, сохраните его. Неважно, кто еще его сохраняет. Ваш объект не имеет ничего общего с этими другими объектами. Вы хотите это, сохраните это. С этим покончено, отпустите и установите указатели на ноль . Если вы не установите для него значение nil, а все остальные также выпустят его, у вас будет свисающий указатель на объект, который был отменен, и это вызовет сбои и много обид.

так вот:

[ffv release]; // you can release it now since the view has ownership of ffv
ffv = nil;  // you released it, so that means you don't want it anymore, so set the pointer to nil

если вы все еще хотите его использовать, не выпускайте его, пока не покончили с ним.

0 голосов
/ 29 июля 2011

Ну, я не уверен, что «потерять» право собственности - правильный термин.В Objective-C вы должны тщательно распределить свое владение объектом.Если вы создаете или сохраняете объект, вы несете ответственность за его освобождение (напрямую или через пул автоматического выпуска).Однако, когда вы вызываете release, вы не теряете ссылку на объект, если что-то еще сохранило его, он все равно останется в памяти, и ваш указатель по-прежнему потенциально может указывать на него.

У вас естьуказатель ffv, который является просто указателем на какую-то память, и у вас есть объект, который создается в первой строке, на которую указывает ffv.

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

Строка [ffv testMethod] может не работать, так как она следует заrelease и может не указывать на действительный объект.Это работает только потому, что что-то еще поддерживает это.ffv по-прежнему имеет то же значение адреса, которое было при первом назначении.

Итак, по порядку:

  1. Ваш вывод правильный.
  2. Не совсем.
  3. Вы не должны использовать ffv после вызова release.У вас нет гарантии, что объект будет там для вас.

Это указатели, которые мы используем здесь, а не ссылки, как вы найдете в Java или C #.Вы должны упорядочить свое владение объектом, создать его, иметь некоторые указатели на него, и, тщательно управляя вызовами retain и release, вы сохраняете его в памяти до тех пор, пока он вам нужен.

0 голосов
/ 29 июля 2011

Объект не является освобожденным до тех пор, пока счетчик удержаний не станет равным 0. Пока он не освобожден, вы можете без проблем использовать его.Сохраняя его, вы гарантируете, что он не будет освобожден под вашими ногами;однако, если вы сохраняете другой объект, который, как вам известно, сохраняет первый объект, вы можете избежать этой формы «косвенного сохранения».Не жалуйтесь, когда вы перемещаете вещи позже, и все начинает ломаться.

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