Возврат объекта, инициализированного через "удобный конструктор"
Когда метод экземпляра возвращает значение, которое было инициализировано с помощью вспомогательного конструктора, нужно ли мне сохранить этот объект и затем автоматически выпустить его при возврате, чтобы при автоматическом выпуске вспомогательного конструктора объект не удалялся.
Будет ли это описание релиза перед вызывающим кодом и станет ли владельцем с сохранением или чем-то?
- (NSStringMutable *)test {
NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
return description;
}
Или так должно быть?
- (NSStringMutable *)test {
NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
[description retain];
return [description autorelease];
}
Телефонный код:
NSMutableString *testVar = [[NSMutableString alloc] initWithString:[object description]];
5 ответов
Нет, вы должны быть в порядке с:
- (NSStringMutable *)test
{
return [NSMutableString stringWithString:@"Test Value"];
}
Это оставит объект со счетом сохранения 1 и будет в пуле автоматического выпуска.
Пул автоматического выпуска сливается в определенное время - он не похож на сборщик мусора. Если вы реализуете обработчик событий (например, обработчик нажатий на кнопки), пул автоматического выпуска очищается платформой при возврате из кода обработки событий.
Если бы вы использовали это:
- (NSStringMutable *)test
{
NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
[description retain];
return [description autorelease];
}
... тогда объект будет иметь счет сохранения 2 и будет дважды находиться в пуле автоматического выпуска, и фактически будет вести себя так же, как в предыдущем примере кода.
Вы можете просто вернуть его. Это одна из основных целей авто-релиза. Если вы не настроили собственный пул автоматического выпуска, пул не будет удален до следующего запуска цикла обработки событий. Руководство по программированию управления памятью объясняет все это в деталях - вы должны читать это, пока не почувствуете себя комфортно.
Примечание: если это было небезопасно, и пул авто-выпусков собирался рано израсходовать по какой-то причудливой причине, предоставление ему двух резервов и двух авто-выпусков не имело бы никакого значения. Числа все еще сбалансированы, так что в какой-то момент они все равно будут выпущены из существования.
Я уже проголосовал за правильный ответ, я добавляю это как примечание стиля:
Ваш код вызова не будет работать, потому что он вызывает [object description]
когда он должен звонить [object test]
Вам не нужно возвращать изменяемые строки, если вы действительно не хотите иметь возможность изменять строку. Я лично стараюсь свести к минимуму изменчивость в коде, который я пишу, потому что я чувствую, что легче поддерживать программы, в которых изменения состояния минимальны. Вы только возвращаете описание, поэтому я не думаю, что оно должно быть изменчивым. Я знаю, что это только пример кода, так что, может быть, я слишком разборчив
Вы можете переписать это как:
-(NSString *)description {
// Just return a static NSString. No need to worry about memory management.
return @"Test Value";
}
И если вы хотите иметь возможность изменить значение этой возвращаемой строки в вашем коде вызова:
NSMutableString *testVar = [[NSMutableString alloc]initWithString:[object description]];
Поскольку вы вызвали alloc для этой строки, вы являетесь ее владельцем и несете ответственность за ее выпуск в будущем.
Кроме того, вы можете использовать один из моих любимых фрагментов кода:
NSMutableString *testVar = [[object description] mutableCopy];
Это вернет изменчивую копию даже неизменного объекта (если, конечно, он соответствует протоколу NSMutableCopying). И вам нужно отправить [testVar release]
на каком-то этапе.
И связать это как фактический ответ на ваш вопрос: если вы отправляете alloc, copy, mutableCopy или сохраняете объект, то вы являетесь владельцем объекта и несете ответственность за отправку ему сообщения о выпуске. Вы можете предположить, что все остальное возвращает автоматически выпущенный объект.
Опять же, я знаю, что это лишь небольшой пример кода, к которому вы задали вопрос, но если вы будете следовать вышеупомянутому правилу, у вас будет решено большинство проблем с управлением памятью. В первом примере вы не отправляли ни одного из них для сообщений, поэтому вам не нужно освобождать память самостоятельно. Тем не менее, у вас есть alloc
в вашем коде вызова, так что вы владеете testVar
и вам нужно выпустить его.
Нет, вы можете просто вернуть автоматически выпущенное значение. Причина этого в том, что autorelease не является функцией самой переменной, это функция пула autorelease, который (если вы не создаете его самостоятельно) обычно управляется циклом выполнения.
Вы близки со вторым, но вам не нужно удержание для случая, о котором вы здесь говорите, и на самом деле вам не нужно вызывать авто-релиз самостоятельно.
Это верно, так как stringWithString уже будет возвращать объект с автоматическим освобождением:
- (NSStringMutable *)test
{
return [NSMutableString stringWithString:@"Test Value"];
}
В общем, при создании объектов с использованием Objective-C, если вы вызываете вспомогательный конструктор (не вызывая alloc и init), возвращаемое значение всегда автоматически высвобождается, поэтому stringWithString возвращает автоматически высвобождаемый объект, который вы можете просто вернуть.