задача-управление памятью - PullRequest
       9

задача-управление памятью

0 голосов
/ 09 сентября 2010

У меня есть несколько вопросов об управлении памятью target-c,

скажем:

NSString * test= [[NSString alloc] init ]
test=@"msg";
[object setStr1: test ]; // declared as: @property(copy, readwrite)
[object setStr2: test ]; // declared as: @property(retain, readwrite)
[object setStr3: test ]; // declared as: @property(assign, readwrite)

test=@"some other string"

Я думаю, str1 будет иметь копию содержимого test: str1 будет указывать на один адрес памяти (кучи), который содержит msg, этот адрес не совпадает с указанным test , право

о стр.2:
1. что это хранит ?, я думаю, тот же адрес, который указывает test, но это увеличит счетчик ссылок с test до 2.
2. когда я изменяю содержание теста, что имеет str2? Я думаю, это все еще указывает на msg

о str3: это неправильно, верно ?, что делает assign?

спасибо.

бонусный вопрос:

NSString * test= [[NSString alloc] init ]
test=@"msg";
test=@"something";

Должен ли я выпустить тест до изменения его содержимого?

Ответы [ 2 ]

3 голосов
/ 09 сентября 2010

Самая важная вещь, которую нужно здесь убрать : оператор присваивания = никогда не изменяет (то есть изменяет) объект. Мутирование объекта может быть достигнуто только путем отправки ему сообщений (например, отправка appendString: на NSMutableString). Оператор присваивания просто заставляет указатель указывать на объект, отличный от ранее.

Таким образом, неверно говорить:

(1) NSString * test = [[NSString alloc] init];
(2) test = @"msg";

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

Кроме того, вам никогда не нужно alloc строковый литерал; компилятор делает это неявно, когда вы используете синтаксис @"...". В общем, вам очень редко придется использовать [NSString alloc] вообще (только если вы хотите использовать различные init* методы, такие как initWithFormat: и т. Д.)

  1. str1 будет указывать на отдельную копию тестовой строки. (Ошибка: согласно Eiko, получатель будет просто воспринимать это как «удержание», если оно неизменное. Это не имеет практического значения, если вы ведете себя правильно.)
  2. str2 будет указывать на то же место, что и тест, и счетчик сохраняемых объектов будет увеличиваться.
  3. str3 будет указывать на то же место, что и тест, но счет сохранения не будет увеличиваться.

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

1 голос
/ 09 сентября 2010

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

Ваш вывод на str1 неверен, потому что копия может просто возвращать себя для неизменяемых типов (они все равно не меняются, поэтому часто система достаточно умна, чтобы держать их только один раз).

str2 действительно будет указывать на тот же объект и просто увеличивать счетчик сохраняемых данных. Вы не можете изменить содержимое теста, так как оно неизменное . Если бы это было NSMutableString, то да, str2 также показал бы это изменение.

Назначение для str3 будет просто «копировать адрес», поэтому он указывает на тот же объект (как str2), но он не сохраняет его, поэтому он не претендует на владение / интерес в этот объект. Если вы выпустите его в другом месте, str3 будет указывать на мертвую память.

Бонус: Как и в моем представлении, да, вы утечки. Присвоение @ "msg" приводит к утечке исходного объекта, а @ "msg" создаст новый.

...