NSString скопировать или разместить? Тебе повезло? - PullRequest
2 голосов
/ 16 ноября 2011

У меня есть поток, который нуждается в информации из графического интерфейса пользователя перед запуском. Сначала я по ошибке попытался создать указатели на поля NSTextFields следующим образом:

NSString *info = [gui_field stringValue];

//launch thread
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

Это вызывало проблемы, когда я пытался манипулировать «информацией» из потока. Я предполагаю, что это так, потому что технически он все еще указывал на строковое представление NSTextField вне потока.

Это решило проблему:

NSString *info = [[gui_field stringValue] copy];

Я предполагаю, что это была сделанная копия (с собственным пространством памяти), которая вообще не использовала NSTextField. Я также предполагаю, что это должно быть поточно-ориентированным.

Это подходящий способ сделать это? Я полагаю, я мог бы сделать это:

NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];

Дают ли два одинаковых результата? И нужно ли явно вызывать release для строки при использовании «copy» или она автоматически высвобождается по умолчанию?

Обновление: или, возможно, я мог бы просто отправить указатель на поток и скопировать строку с помощью "autorelease", добавив ее в пул автоматического выпуска потока:

NSString *info = [gui_field stringValue];

//launch thread
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *copied_str = [[info copy] autorelease];

    //do stuff

    [pool drain];
    //copied_str should now be history
}

Таким образом, мне не нужно беспокоиться о явном освобождении copied_str. Он исчезнет, ​​как только закончится нить.

Ответы [ 2 ]

4 голосов
/ 16 ноября 2011

Не нужно полагаться на удачу:)

alloc, copy, new и mutableCopy означают, что вы являетесь владельцем объекта. Оба из них дадут вам оставленный объект. Если вы управляете памятью, вам нужно освободить ее.

По соглашению, другие методы предоставят вам автоматически освобожденный объект.

Например, если вы хотите автоматически освобождать объект, вы можете вызвать:

NSString *str = [NSString stringWithString:yourString];

См. Руководство по управлению памятью:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

В частности, четыре правила здесь:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

Вам принадлежит любой созданный вами объект

Вы создаете объект, используя метод, имя которого начинается с «alloc», «new», «copy» или «mutableCopy» (например, alloc, newObject или mutableCopy).

Наконец, оба копируют строку.

из документов NSString:

initWithString: Возвращает объект NSString, инициализированный путем копирования символов из другой заданной строки.

копия из NSObject. Он определяет копию как:

Возвращаемое значение Объект, возвращаемый методом протокола NSCopying copyWithZone :, где зона равна nil.

NSString реализует протокол NSCopying, поэтому copy возвращает копию строки.

Существует одно исключение, когда строка не копируется initWithString - если вы передадите строковый литерал, он обернет указатель на константу и проигнорирует сохранение / освобождение. Смотрите здесь, если вам интересно: Разница между NSString литералами

2 голосов
/ 16 ноября 2011
NSString *info = [[gui_field stringValue] copy];
NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];

Те, кто делают одно и то же.

[self performSelectorInBackground:@selector(myMethod:) withObject:info];

-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *copied_str = [[info copy] autorelease];

Нет, ты не можешь этого сделать. Даже для доступа к строковому объекту GUI просто для копирования его может быть достаточно для сбоя.

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

NSString *info = [[gui_field stringValue] copy];

//launch thread
//pass ownership to callee
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

// myMethod owns info!
-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [info autorelease];

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

«Я попросил аргумент».

«Это оскорбление».

...