Как я могу исправить это предупреждение clang: «Объект с +0 счетами удержания возвращается вызывающей стороне, где ожидается +1 (счет владения), сохраняющий счет»? - PullRequest
10 голосов
/ 15 мая 2010

У меня есть фрагмент кода Objective-C, который выглядит следующим образом:

- (NSString *)copyData:(NSData *)data
{
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"];
    NSLog(@"Copying data to %@", path);
    [data writeToFile:path atomically:NO];
    return path;
}

Код вызывается из инициализатора, который выглядит следующим образом:

- (id)initWithData:(NSData *)data
{
    if ((self = [super init]) != nil) {
        NSString *path = [self copyData:data];        // Line 41 (referenced in warning, shown below)
        return [self initWithContentsOfFile:path];
    }
    return self;
}

При запуске статического анализатора clang я получаю следующие предупреждения для переменной path:

Потенциальная утечка объекта, выделенного в строке 41 и сохраненного в «пути»

Объект с +0 счетами удержания, возвращаемыми вызывающей стороне, где ожидается +1 (обладание) счетом удержания

Я в замешательстве. Насколько я понимаю, stringByAppendingPathComponent должен возвращать автоматически освобожденную строку, поэтому он должен иметь чистое количество сохраняемых счетчиков 0. (Очевидно, я не хочу сохранить его.)

Я пытался изменить copyData:, чтобы вернуть следующее, но это не избавило от предупреждения:

return [[path retain] autorelease];

Так в чем же дело с этим предупреждением?

Ответы [ 5 ]

15 голосов
/ 15 мая 2010

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

В вашем случае, конечно, вы имеете в виду файлы и все такое, так что это игнорируемое предупреждение. Если вы поменяете название вашего метода на что-то вроде saveData:, то держу пари, что предупреждение исчезнет.

9 голосов
/ 06 августа 2010

Кроме того, в тех случаях, когда вы действительно хотите назвать метод с «копией» или чем-то еще, потому что независимо от рекомендаций по управлению памятью Какао, копия является лучшим именем для метода, вы можете аннотировать объявление метода с помощью NS_RETURNS_NOT_RETAINED и тогда Clang не даст вам предупреждение. Итак:

// Copies data from data to string; does not follow the copy rule
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED;
4 голосов
/ 15 мая 2010

Нет, это неправильно; если метод не содержит «alloc», «copy», «new» или одно из других ключевых слов, которое подразумевает, что объект будет принадлежать invoker, метод возвращает автоматически освобожденный или иным образом управляемый объект, поэтому stringByAppendingPathComponent возвращает автоматически освобожденную строку .

Кроме того, ваш метод «copyData» содержит слово «copy», означающее, что результат должен принадлежать (и освобождаться) вызывающей стороне. Тем не менее, возвращенный вами результат был автоматически выпущен, следовательно, выдается сообщение об ошибке. Если вы хотите исправить ошибку, не делайте авто-релиз. То есть:

 return [path retain]

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

Название "copyData", ИМХО, все равно не интуитивно понятно. Я бы предложил вам переименовать вашу функцию в «pathToSavedDataWithData» или тому подобное. То, что говорит о том, что он на самом деле делает.

4 голосов
/ 15 мая 2010

Поскольку метод имеет имя copy, анализатор ожидает, что возвращенный объект будет иметь счет сохранения +1, согласно Руководству по управлению памятью .

0 голосов
/ 19 февраля 2011

Я собираюсь сделать попытку и предположить, что вы получите точно такое же сообщение об ошибке, независимо от того, начиналось ли название вашей подпрограммы с «copy ...» или нет. Я просто оказался в похожем сценарии, и «копия» не была частью названия подпрограммы, которую я вызывал. Clang выдавал сообщение об ошибке просто потому, что я возвращал автоматически освобожденный объект, опасная ситуация. Делать

  return [path retain]  

трюк в конце, как рекомендовано Майклом, позаботился о проблеме.

...