Рассмотрим два следующих метода чтения строки из файла:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
NSData *data = [file readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[file closeFile];
Я бы предпочел полагаться на метод №1, но он ведет себя странно при использовании в следующем контексте:
NSString *string; // CLASS VARIABLE
(void) setupView
{
string = ...; // LOADING THE STRING
}
(void) drawView
{
...; // USING THE STRING
}
Короче говоря, это цикл рисования OpenGL-ES, основанный на NSTimer. Проблема в том, что строка доступна только в первом кадре. В следующем кадре имитатор iPhone (2.2) дает сбой при попытке доступа к строке.
Вероятно, «что-то в моем коде или в коде OpenGL-ES, который я использую» можно было бы сказать ... Но как объяснить тот странный факт, что если я использую метод № 2 для загрузки строки, все работает как задумано?
Какие-нибудь подсказки?





Когда вы создаете String с помощью метода Class, он обычно добавляется в самый верхний пул автозапуска. В конце цикла событий пул отправляет сообщение о выпуске всем объектам, которые он содержит. В этом случае вновь созданная строка имеет счетчик сохранения, равный 1, а в конце цикла он достигает 0 и освобождается. Если вы хотите сохранить строку, отправьте ей сообщение о сохранении, чтобы сохранить положительный счетчик при завершении цикла событий.
В Какао вы являетесь владельцем объекта, только если вы создаете его с помощью alloc, new, copy или retain. Если у вас нет объекта, у вас нет никаких гарантий относительно этого объекта за пределами локальной области видимости, в которой вы его используете. В вашем примере, поскольку вы не создали новую строку ни одним из вышеупомянутых методов, у вас нет гарантии, что она появится позже, если вы ее сохраните.
Для того, чтобы стать владельцем объекта (т. Е. Вы хотите, чтобы он оставался, чтобы вы могли использовать его позже), которым вы еще не владеете (т. Е. Вы не создали его с помощью одного из ранее упомянутых методов) , вы должны отправить этому объекту сообщение о сохранении. Например, если вы переписываете свой код, как показано ниже, строка будет принадлежать вам, и вам не придется беспокоиться об ее использовании позже:
// option 1
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [[NSString alloc] initWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
// option 2
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
[string retain];
Вариант 1 подходит, потому что вы специально создаете строку с сообщением alloc. Теперь вы владеете строковым объектом, пока не откажетесь от владения в другой раз. Вероятно, это лучший вариант для вас, учитывая ваши конкретные обстоятельства (т.е. вы действительно не хотите использовать удобный конструктор, потому что вы хотите, чтобы строковый объект оставался без дела для использования позже).
Вариант 2 приемлем, потому что вы конкретно становитесь владельцем строки, отправляя ей retain. В вашем случае это, вероятно, не лучший вариант, потому что вариант alloc/init уже доступен, и его обычно легче читать.
Когда вы закончили работу с объектом и хотите отказаться от владения объектом, вы отправляете этому объекту сообщение release. Важно помнить, что в Какао отправка объекту сообщения release не означает, что вы его уничтожаете, просто вы отказываетесь от владения.
Управление памятью какао построено на идее владения объектами. Хотя поначалу это может немного сбивать с толку, как только вы осознаете это, это значительно упрощает программирование в среде, не вызывая ошибок памяти, утечек или других ошибок. Комфортные методы (например, stringWithString) действительно предназначены для использования, когда вы хотите создать объект, который вы действительно используете только в течение короткого периода времени и в рамках одной функции или программного блока. Если вы планируете оставить объект за пределами этой области, предпочтительнее использовать методы alloc/init или new для создания объекта.
Для получения дополнительной информации прочтите Руководство по программированию управления памятью для какао. Это действительно считается обязательным чтением для разработчиков Cocoa. Кроме того, обычно требуется прочитать его, поэкспериментировать и прочитать еще несколько раз, чтобы по-настоящему понять, особенно если у вас есть большой опыт работы с другими моделями управления памятью.
О, теперь я понял! Читайте больше по теме на stackoverflow.com/questions/6578/…