NSString - строкаWithFormat против строкиWithString - PullRequest
1 голос
/ 22 февраля 2011

У меня есть глобальная переменная NSString, объявленная в файле .m.Когда я использую stringWithFormat, чтобы дать ему строковое значение в любом месте файла .m, это значение не сохраняется между вызовами функций.Однако, когда я делаю то же самое, используя stringWithString, значение сохраняется в течение всей реализации и при вызове любых функций, что дает ему истинное глобальное поведение.Вместо того, чтобы выразить это иначе, как внутреннее управление памятью для stringWithFormat и stringWithString?

Почему значение сохраняется для stringWithString при выдаче «сообщения, отправленного на освобожденный экземпляр» (при последующем использовании NSString, скажем, в операторе NSLog в другой функции, которая идет после функции, которая передала NSString значение, используяstringWithFormat) при использовании stringWithFormat?Нет таких проблем, когда я заменяю то же самое на stringWithString.

Спасибо!

РЕДАКТИРОВАТЬ: я забыл упомянуть, что ДА это работало в случае stringWithFormat, когда я выполнял ручное сохранение позже.Значение сохранилось.Отсюда вопрос.

Ответы [ 2 ]

3 голосов
/ 22 февраля 2011

Похоже, что вы не сохраняете строку, и из-за этого, когда вы попытаетесь получить к ней доступ позже, она была освобождена. Если вы не знакомы с управлением памятью, взгляните на Руководство по программированию управления памятью от Apple.

Причина, по которой -stringWithString: не прерывается, вероятно, потому что компилятор выполняет некоторую оптимизацию со строковыми литералами; Он просматривает программу и сохраняет только одну ссылку на идентичные строки, которые определены. Благодаря этому ваш указатель будет оставаться действительным в течение всего времени жизни приложения.

Вы не должны полагаться на это. Вы не можете гарантировать, что все компиляторы выполнят эту оптимизацию. Сохраните переменную, когда создадите ее, и отпустите, когда она перестанет в ней нуждаться.

2 голосов
/ 22 февраля 2011

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

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

Это просто покрывает ваше неправильное управление памятью. И вам определенно не следует полагаться на это поведение.


Edit. больше сказать нечего. NSString, созданный с помощью stringWithString: literal, будет просто указывать на расположение литерала в памяти.

Небольшой пример:

NSString *string = @"Foo";
NSLog(@"%@ - %p", string, string);
NSString *string2 = string;
NSLog(@"%@ - %p", string2, string2);
NSString *string3 = [string copy];
NSLog(@"%@ - %p", string3, string3);
NSString *string4 = [string retain];
NSLog(@"%@ - %p", string4, string4);
NSString *string5 = [NSString stringWithString:string];
NSLog(@"%@ - %p", string5, string5);
NSString *string6 = [[NSString alloc] initWithString:string];
NSLog(@"%@ - %p", string6, string6);

вы увидите, что все они указывают на один и тот же адрес.

2011-02-22 13:24:41.202 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.207 xxx[40783:207] Foo - 0x74120

И все они никогда не будут освобождены. Таким образом, вы можете получить доступ к string5 из другого метода в вашем коде, и он все равно будет указывать на адрес 295740, и строка NSString «Foo» все равно будет там.

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

Вы нарушаете правила управления памятью, но никогда не заметите этого, если будете использовать только строковые литералы. Пока поведение компилятора не изменится.

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

...