Как я могу исправить это предупреждение о лязгах: объект с +0 счетчиками удержаний, возвращенных вызывающей стороне, где ожидается +1 (владеющий) счетчик удержаний?

У меня есть фрагмент кода 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 и сохраненного в 'path'

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

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

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

return [[path retain] autorelease];

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


person mipadi    schedule 14.05.2010    source источник


Ответы (5)


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

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

person Ben Zotto    schedule 14.05.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;
person Jason Coco    schedule 06.08.2010
comment
Этот ответ убрал так много неверных предупреждений из моего проекта! - person Rik Smith-Unna; 03.04.2012

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

person Dave DeLong    schedule 14.05.2010

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

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

 return [path retain]

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

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

person Michael Aaron Safyan    schedule 14.05.2010

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

  return [path retain]  

уловка в конце, рекомендованная Майклом, решила проблему.

person hkatz    schedule 19.02.2011
comment
Ой! Могу я прокомментировать свой ответ? Оказалось, что название моего распорядка началось с нового ... так что, похоже, я немного поторопился. Теперь я знаю лучше. :-) - person hkatz; 19.02.2011