Что может повлиять на срок службы строки NSString, возвращаемой stringWithContentsOfFile "? - PullRequest
0 голосов
/ 14 января 2009

Рассмотрим 2 следующих метода чтения строки из файла:

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 для загрузки строки, все работает как предназначена?

Есть какие-нибудь подсказки?

Ответы [ 2 ]

4 голосов
/ 14 января 2009

В Какао у вас есть объект, только если вы создаете его с помощью 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 для создания объекта.

Для получения дополнительной информации, пожалуйста, прочитайте Руководство по программированию управления памятью для какао . Это действительно считается обязательным чтением для разработчиков какао. Кроме того, обычно требуется его чтение, эксперименты и чтение еще несколько раз, чтобы понять, особенно если у вас есть большой опыт работы с другими моделями управления памятью.

1 голос
/ 14 января 2009

Когда вы создаете String с методом Class, он обычно добавляется в самый верхний пул авто-релиза. В конце цикла событий пул отправляет сообщение об освобождении всем объектам, которые он содержит. В этом случае вновь созданная строка имеет счет сохранения, равный 1, и в конце цикла достигает 0 и освобождается. Если вы хотите сохранить строку, отправьте ей сообщение сохранения, чтобы сохранить счетчик положительным после завершения цикла событий.

...