Где я должен назвать [выпуск объекта]? - PullRequest
1 голос
/ 03 мая 2010

Я переклассифицировал некоторые UITextField и добавил некоторые пользовательские свойства.

В UITableViewController, в ViewDiDLoad я их инициирую, а в cellForRowAtIndexPath я добавляю их в ячейку с помощью [cell.contentView addSubview: customTextField];

Каждая ячейка имеет свой собственный customTextField, поскольку все они очень разные.

Где мне следует вызвать [customTextField release]?

После того, как я добавлю их в представление ячейки?

Если, например, я вызову [self.tableView reloadData], мой customTextField будет снова добавлен в ячейку, поэтому, возможно, мне следует изменить свой подход к этому?

спасибо за ориентацию ...

С уважением,

г.

Ответы [ 7 ]

1 голос
/ 03 мая 2010

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

.h

@interface ... {
    UITextField *_customTextField;
}

.m

@property (nonatomic, readwrite, retain) UITextField *customTextField;
...
@synthesize customTextField=_customTextField;

-(void)viewDiDLoad {
    self.customTextField = [[[UITextField alloc] init....] autorelease];
}
...
- (void)dealloc {
   // I do not recommend accessors in dealloc; but everywhere else I do
   [_customTextField release]; _customTextField = nil;
}

Никогда не получить доступ к Ивар непосредственно, за исключением dealloc (даже это является спорным, и некоторые люди рекомендуют self.customTextField = nil; в dealloc; есть аргументы либо способом). Но никогда не назначайте свои ивары напрямую. Если вы будете следовать этому правилу, вы обнаружите, что большинство проблем с памятью исчезают.

1 голос
/ 03 мая 2010

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

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

Редактировать: я действительно должен упомянуть autorelease, но в данном случае это не актуально. Управление памятью лучше всего осуществлять с понятием «владелец» - лицо, которое что-то создает (или сохраняет), должно нести ответственность за его удаление (или release на языке ObjC). autorelease обрабатывает некоторые случаи, когда вам нужно передать объект другому владельцу, который ранее владел им самостоятельно (обычно через метод return). Если вы являетесь создателем, вы не можете просто release передать его перед возвратом новому владельцу, поскольку он будет удален до того, как новый владелец сможет заинтересовать его. Тем не менее, вы не можете просто не release это; это будет течь. Таким образом, система предоставляет большой список объектов, которые она выпустит от вашего имени в будущем. Вы передаете свою release ответственность за этот список, а затем return объект новому владельцу. Этот список (пул авто-выпусков) гарантирует, что ваше освобождение произойдет в какой-то момент, но дает новому владельцу возможность заявить об объекте как о своем, прежде чем он будет выпущен.

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

1 голос
/ 03 мая 2010

Я всегда освобождаю свои элементы управления сразу после добавления их в представление с помощью addSubView. Когда я работаю с таблицами, я также инициализирую их в методе cellForRowAtIndexPath.

Поэтому объект остается живым в кратчайшие сроки.

0 голосов
/ 03 мая 2010

Посмотрите на UITableView -dequeueReusableCellWithIdentifier: и -initWithStyle: reuseIdentifier:.

В -tableView: cellForRowAtIndexPath :, используйте -dequeueReusableCellWithIdentifier: и проверьте, равен ли результат нулю. Если это так, создайте новую ячейку с помощью -initWithStyle: reuseIdentifier:.

Отправьте -autorelease в свой customTextField после создания и добавления в соответствующую ячейку.

0 голосов
/ 03 мая 2010

Каждый объект в Obj-C имеет счетчик ссылок (retainCount), и когда этот счетчик становится равным 0, объект освобождается. Когда вы выделяете и инициализируете объект, счетчик ссылок устанавливается на 1, но вы можете сохранять его столько раз, сколько захотите.

UITextField *textField = [[UITextField alloc] init]; // Reference counter = 1
[textField retain]; // Reference counter = 2
[textField retain]; // Reference counter = 3

Противоположностью retain является освобождение, которое вычитается из счетчика ссылок;

...
[textField release]; // Reference counter = 2
[textField release]; // Reference counter = 1

Вы всегда можете получить счетчик ссылок ваших объектов;

printf("Retain count: %i", [textField retainCount]);

Метод addSubview из UIView делает retain ваше переданное в подвиде - и когда это сделано с ним, это освобождает его. Если вам нужен UITextField позже, в другой области действия (когда UIView закончил с ним и выпустил его) - вам не следует release после того, как вы добавили его в суперпредставление. Большую часть времени вам фактически не нужно держаться за ссылку, поэтому вы должны выпустить ее после того, как добавили ее в суперпредставление. Если вы этого не сделаете - вы можете release сделать это в методе dealloc вашей области видимости.

0 голосов
/ 03 мая 2010

Вы не должны добавлять подпредставление в cellForRowAtIndexPath! Это замедлит представление, так как вы добавляете подпредставление каждый раз, когда отображается ячейка. Для этого попробуйте использовать пользовательский класс UITableViewCell.

Вот идеальное решение для настройки UITableView http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html работает идеально

0 голосов
/ 03 мая 2010

Самый безопасный способ обработки владения объектом - это автоматическое освобождение представления сразу после инициализации:

FooTextField* textField = [[[FooTextField alloc] init] autorelease];
[myCell.contentView addSubview:textField];

Добавление текстового поля в суперпредставление (представление контента UITableViewCell) сохраняет его. Таким образом, вам не нужно заботиться о том, чтобы потом освободить вид.

Похоже, что в сообществе разработчиков iPhone есть негодование по поводу автоматического выпуска. На мой взгляд, это негодование необоснованно. Автоматическое освобождение объекта добавляет очень мало накладных расходов программе, если объекты живут дольше, чем текущий проход через цикл выполнения.

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