Метод возвращает объект Objective C с счетом сохранения +1 - PullRequest
5 голосов
/ 31 июля 2011

После обновления до Lion и, следовательно, до XCode 4.1

Я получаю десятки "потенциальных утечек памяти" при запуске анализатора.

Я бы обычно использовал список свойств следующим образом:

@synthesize indexPath = _indexPath;

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    self = [super initWithNibName:nibName bundle:nibBundle];
    self.indexPath = [[NSIndexPath alloc] init];
    [_indexPath release];
    return self;
}

и в методе dealloc ():

- (void)dealloc {
    [_indexPath release];
    [super dealloc];
}

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

Как вы распределяете и форматируете свой код, чтобы XCode не верил, что он течет? (сохраняя псевдоним свойства self.var vs _var)

Спасибо ...

Ответы [ 5 ]

8 голосов
/ 31 июля 2011

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

NSIndexPath *ip = [[NSIndexPath alloc] init];
self.indexPath = ip;
/* ... */
[ip release];

indexPath = [[NSIndexPath alloc] init];

self.indexPath = [[[NSIndexPath alloc] init] autorelease];

self.indexPath = [NSIndexPath indexPathWithIndex:...];
6 голосов
/ 31 июля 2011

В init вы действительно должны использовать ivars для прямой установки:

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    self = [super initWithNibName:nibName bundle:nibBundle];
    _indexPath = [[NSIndexPath alloc] init];
    return self;
}

Возможно, это излечит проблему? Это будет следовать соглашению.

4 голосов
/ 31 июля 2011

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

Другими словами, компилятор не может гарантировать, что self.indexPath == _indexPath, поэтому ваш вызов release может быть для другого объекта, чем тот, который вы получили из метода init. Таким образом, он дает вам предупреждение о том, что ваше управление памятью может быть неправильным, что уместно.

Таким образом, вам нужно гарантировать, что вы вызываете release для того же объекта, который вы передали в установщик. Короче говоря:

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;

[tmpPath release];           // This is the only correct way to do it.
// [self.indexPath release]; // WRONG! May not be the same object as tmpPath
// [_indexPath release];     // WRONG! May not be the same object as tmpPath

Однако, как уже упоминали другие, в методе init обычно лучше просто назначить ivar напрямую. Таким образом:

_indexPath = [[NSIndexPath alloc] init];
2 голосов
/ 31 июля 2011

Статический анализатор, вероятно, просто смотрит на эту строку, поскольку он недостаточно умен, чтобы понять, что вы на самом деле пытались устранить проблему.

Я бы использовал этот шаблон

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;
[tmpPath release];

Более подробное объяснение. Поэтому, когда анализатор смотрит на линию

self.indexPath = [[NSIndexPath alloc] init];

Видит, что +1 удерживает из этой части

[[NSIndexPath alloc] init]

и он видит, что self.indexPath скомпилирован в

[self setIndexPath:[[NSIndexPath alloc] init]];

Этот метод (если автоматически сгенерирован @synthesize), вероятно, будет выглядеть следующим образом

- (void)setIndexPathL(NSIndexPath *)indexPath
{
    if (_indexPath != indexPath) {
        [_indexPath release];
        _indexPath = [indexPath retain];
    }
}

Так что теперь анализатор видит, что есть еще retain на indexPath.

Таким образом, это 2 x +1 retain, и можно предположить, что вы освободите только один раз в раздаче.

2 голосов
/ 31 июля 2011

Попробуйте это:

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;
[tmpPath release];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...