различные методы выделения / инициализации / сохранения объекта в target-c - PullRequest
1 голос
/ 01 июня 2010

В нескольких примерах примера кода target-c я видел, как люди создают новые объекты, подобные этому:


RootViewController *viewController = [[RootViewController alloc] init];
self.rootViewController = viewController; // self.rootViewController is a (nonatomic,retain) synthesized property
[viewController release];
[window addSubview: [self.rootViewController view]];

Это что-то другое "за кадром", чем делать это, как это вместо этого?


self.rootViewController = [[RootViewController alloc] init];
[window addSubview: [self.rootViewController view]];

Редактировать: позже я выпускаю rootViewController в моем методе dealloc:


-(void) dealloc {
    [rootViewController release];
    [super dealloc];
}

Мне просто интересно узнать синтаксис между ними. Кажется, один создает временный объект viewController, а другой размещает / вводит его непосредственно в self.rootViewController.

Кажется, это немного более просто / упрощенно, поэтому мне интересно, почему кто-то выбрал бы первый метод.

Спасибо!

Ответ: Таким образом, похоже, что при использовании второго метода он вызывает утечку памяти, потому что объект rootViewController на самом деле имеет счет сохранения 2. (Смотрите мой ответ ниже со ссылкой на пост, который подробно объясняет это.) Спасибо всем!

Ответы [ 5 ]

3 голосов
/ 01 июня 2010

Эта строка:

self.rootViewController = viewController

идентично этой строке:

[self setRootViewController:viewController];

Типичный вызов setX освобождает ранее сохраненное значение X и назначает новое сохраненное значение X.

id old = X;
X = [new retain];
[old release];

Но он может делать и все остальное.

Если вы знаете, что не существует текущего значения для освобождения (в init), и функция установки ничего не делает, кроме как сохраняет новое значение (синтезированное), вы можете заменить:

RootViewController *viewController = [[RootViewController alloc] init];
self.rootViewController = viewController; // self.rootViewController is a (nonatomic,retain) synthesized property
[viewController release];

С:

rootViewController = [[RootViewController alloc] init];

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

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

self.rootViewController = [[[RootViewController alloc] init] autorelease];

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

2 голосов
/ 01 июня 2010

Ваш второй фрагмент кода не освобождает созданный вами объект.

self.rootViewController - это свойство, которое сохраняет объект. Итак, вы создаете объект с использованием alloc, а затем метод setter для self.rootViewController также сохранит его. Вы должны освободить все объекты, которые вы выделили. Всегда

Что происходит, это:

  1. Вы создаете объект типа RootViewController, используя alloc , поэтому счетчик сохранения становится 1
  2. Объект присваивается свойству, которое также сохраняет объект. Таким образом, счет удержания становится 2

Когда позднее self будет освобожден, сохраненный объект RootViewController будет освобожден, поэтому его счетчик хранения снова станет 1 .

Результат: у вас утечка памяти.

1 голос
/ 01 июня 2010

Во втором фрагменте кода будет утечка памяти, потому что вы пропустите строку [self.rootViewController release].

Более подробно:

  • Когда вы вызываете [[RootViewController alloc] init], количество сохраненных созданных объектов будет равно 1.
  • Вызов self.rootViewController = viewController увеличит его до 2, поскольку свойство self.rootViewController сохраняется.
  • Вызов [viewController release] уменьшает счет удержания до 1
  • Так что если вы вызовете self.rootViewController = nil позже, то счетчик сохранений будет равен 0 (потому что созданный установщик вызывает метод release), поэтому объект будет освобожден.

Во втором случае счет удержания будет равен 1 при вызове self.rootViewController = nil, поэтому объект никогда не будет освобожден.

Если вы хотите более компактное решение, попробуйте это:

self.rootViewController = [[[RootViewController alloc] init] autorelease];
[window addSubview: [self.rootViewController view]];
0 голосов
/ 06 сентября 2010

Спасибо, ребята, за ваши ответы! Я искал меньше ответов типа «прочитайте руководство по управлению памятью» и больше ответов типа «тупой», «вот фон и разница между этими двумя методами, изложенными для вас». Я знаком с владением объектами, сохранением количества и т. Д., Но я не понял, ПОЧЕМУ было важно использовать ** self. ** rootViewController и ПОЧЕМУ второй фрагмент кода просочился ... и буквально "за кадром" Разница между двумя. Поэтому я наткнулся на этот пост, который, как мне кажется, был точным ответом, который я искал ... (Надеюсь, он точный!) :) но в любом случае я ставлю галочку ole Филиппу, потому что он ответил первым. Я просто не понял его ответа, пока не прочитал следующий пост ...

http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-properties-newbie.html

Эта часть была ключевой для меня:


Что бы произошло, если бы вы написали:

self.obj = [[SomeObject alloc] init];

В этом случае вы держитесь за объект с сохраняемым счетчиком, равным двум - первый счет берется из «alloc», а второй добавляется установщиком.

Чтобы освободить эту переменную, вам нужно сделать что-то вроде этого:

[obj release];
self.obj = newValue;

так, чтобы "release" вызывался дважды для объекта. Если вы пропустите дополнительный «релиз», то, когда указатель будет перезаписан, объект все еще будет перемещаться с сохранением количества единиц и, таким образом, не будет освобожден. Мгновенная утечка памяти.


Еще раз спасибо!

0 голосов
/ 01 июня 2010

Пожалуйста, прочитайте и поймите Правила управления памятью какао . Вы получили объект с помощью alloc, поэтому вы им владеете. Под «вами» я подразумеваю исполняемый код в текущей области видимости. Вам необходимо или выпустить или автоматически выпустить его, чтобы отказаться от права собственности. Присвоение объекта чему-либо другому (в данном случае имуществу) не освобождает вас от ответственности за отказ от владения, когда это сделано.

Ваш второй пример протекает. Вы можете исправить это так:

self.rootViewController = [[[RootViewController alloc] init] autorelease];

В Mac OS X то, используете ли вы это или ваш первый пример, является вопросом предпочтительного стиля. В случае с iPhone первый пример, как правило, предпочтительнее, поскольку он не включает добавление объекта в пул автоматического выпуска. Сказав это, поскольку контроллеру представления, вероятно, потребуется остаться за пределами конца текущего события, это не имеет большого значения.

Между прочим, в двух ответах упоминается сохранение количества, и оба они верны, но лучше вообще не думать о сохранении счета и думать только с точки зрения владения. Сохраненные значения являются подробностями реализации.

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