Управление памятью - PullRequest
       16

Управление памятью

1 голос
/ 15 мая 2011

Как работает метод removeFromSuperView: действительно работает? У меня проблема с плохим доступом к памяти, когда я хочу переустановить представление

- (id)init {
   if (!(self = [super init]))
      return nil;

   _mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
   NSLog(@"retainCount :%d", [_mainView retainCount]);
   UIButton *reInitButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f,0.0f,90.0f,35.0f)];      
   [reInitButton addTarget:self action:@selector(buttonDidTapped:) forControlEvents:UIControlEventTouchUpInside];
   [[self view] addSubView:_mainView];
   NSLog(@"retainCount :%d", [_mainView retainCount]);
   [_mainView release];
   NSLog(@"retainCount :%d", [_mainView retainCount]);

   return self;
}

- (void)buttonDidTapped:(id)sender {
   [_mainView removeFromSuperView]; //crash during second times press the button
   NSLog(@"retainCount :%d", [_mainView retainCount]);
   _mainView = [[UIView alloc] initWithFrame[[UIScreen mainScreen] bounds]];
   [[self view] addSubView:_mainView];
   NSLog(@"retainCount :%d", [_mainView retainCount]);
   [_mainView release];
   NSLog(@"retainCount :%d", [_mainView retainCount]);
}

У меня есть NSLog каждый раз, когда есть ключевое слово retain, alloc или release. И результат очень странный.

//init
retainCount : 1
retainCount : 2
retainCount : 1
//1st time pressed button
retainCount : 1 //remove super view didn't decrease
retainCount : 2
retainCount : 1
//2nd time pressed button
retainCount : 0 //crash. Memory bad access

Странная вещь - почему он не зависал при первом нажатии ??

Ответы [ 3 ]

3 голосов
/ 15 мая 2011

Я думаю, что ваша проблема здесь:

[_mainView release];

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

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

В качестве полезного совета многим программистам нравится сбрасывать объекты на NULL (или nil в языке objC) после их освобождения, как напоминание о том, что вы не можете использовать этот объект снова. Если вы что-то -release, вам лучше это иметь в виду.

Наконец, я предлагаю вам Google термин «подсчет ссылок» и прочитайте его; это более общая идиома, чем специфика NSObject, и, вероятно, будет полезно подумать об основах и о том, как вы могли бы реализовать это на другом языке, например, на C. Это поможет вам лучше рассуждать об объектах с подсчетом ссылок .

3 голосов
/ 15 мая 2011

НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ОСТАВШИЙСЯ .Извините за то, что поместил это в заглавные буквы, но я не могу понять для жизни меня, почему люди все еще используют это.Это неверный справочник по управлению памятью.Вместо этого используйте инструменты или подобное.

2 голосов
/ 15 мая 2011

Вы не должны получить доступ к _mainView в этот момент. Это может быть трудно объяснить, так что терпите меня. Мы собираемся подсчитать, но не абсолютный счет, просто утверждения вашего кода на объекте.

Вы выделяете память для объекта и указываете на него с помощью _mainView:

_mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

У вас есть 1 право собственности на этот объект. Когда вы добавляете его в качестве подпредставления другого представления, это представление также претендует на право собственности, но это не ваше, а представление. Тот факт, что объект в _mainView застревает, является случайностью, и вы не должны на это полагаться. Затем вы отпускаете объект:

[_mainView release];

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

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

[_mainView removeFromSuperView];

и это вызывает сбой, чего нельзя ожидать, но это не является необоснованным. Позволив заявкам о владении перейти к 0, вы сказали системе: «Мне больше не нужен этот объект. Я не собираюсь получать к нему доступ после этого момента. Если он исчезнет, ​​на меня это не повлияет». На самом деле, однако, вам нужно , чтобы он оставался рядом, и вам нужен доступ к нему.

Что вам нужно сделать, так это переместить строку:

[_mainView release];

внутри действия кнопки, сразу после вызова removeFromSuperview.


* Второй из которых можно избежать, установив _mainView = nil; после его отпускания, в этом случае, но это не решит большую проблему.

...