2009-03-04 2 views
8
//creates memory leak 
    self.editMyObject = [[MyObject alloc] init]; 

//does not create memory leak 
    MyObject *temp = [[MyObject alloc] init]; 
    self.editMyObject = temp; 
    [temp release]; 

Первая строка кода создает утечку памяти, даже если вы выполняете [self.editMyObject release] в методе dealloc класса. self.editMyObject имеет тип MyObject. Во второй строке не происходит утечки памяти. Неправильная ли первая строка или есть способ освободить память?Почему это создает утечку памяти (iPhone)?

+0

Три хорошие ответы. Заметьте, кто и кто ответит. – 4thSpace

ответ

10

Правильное поведение зависит от объявления editMyObject @property. Если предположить, что он delcared в

@property (retain) id editMyObject; //id may be replaced by a more specific type 

или

@property (copy) id editMyObject; 

затем присвоение через self.editMyObject = сохраняет или копирует заданный объект. Так как [[MyObject alloc] init] возвращает сохраненный объект, который вы, как владелец звонящего, у вас есть дополнительное сохранение экземпляра MyObject, и поэтому он будет течь, если только он не будет иметь соответствующий выпуск (как во втором блоке). Я предлагаю вам прочитать Memory Management Programming Guide [2].

Ваш второй блок кода правильный, если свойство объявлено, как описано выше.

p.s. Вы не должны использовать [self.editMyObject release] в методе -dealloc. Вы должны позвонить [editMyObject release] (при условии, что поддержка ivar @property называется editMyObject). Вызов аксессора (через self.editMyObject безопасен для @synthesized accessors, но если overriden accessor полагается на состояние объекта (которое может быть недействительным в вызывающем местоположении в -dealloc или вызывает другие побочные эффекты, у вас есть ошибка, вызвав accessor.

[2] правила владения объекта в какао очень просто: если вы вызываете метод, который имеет alloc или copy в его подписания (или использовать +[NSObject new], которая в основном эквивалентна [[NSObject alloc] init]), то вы «свой» объект, который возвращается, и вы должны сбалансировать свое владение с помощью release. Во всех остальных случаях вы не являетесь владельцем объекта, возвращенного из метода. Если вы хотите сохранить его, вы должны взять на себя ответственность с retain и более поздней версией права собственности с release.

+0

У меня есть NSMutableArray. Я установил его для копирования, но когда я это сделаю [self.List addObject: myobject], я получаю неперехваченное исключение. Вернуть его, чтобы сохранить работу отлично. Какие-либо предложения? – 4thSpace

+0

Я считаю, что @property (копия) будет использовать -copy для создания копии, даже если новое назначение является изменяемым типом.Таким образом, вы получаете неизменяемую копию (обычно вы используете -mutableCopy для создания изменчивой копии), вызывая исключение при попытке изменить присвоенное значение .... –

+0

[продолжение] Вы можете использовать @property (сохранить) и назначить как self.List = [[mutableArr mutableCopy] autorelease]. –

8

Ваша собственность объявлена ​​«сохраненной», что означает, что переданный объект автоматически сохраняется.

Поскольку у вашего объекта уже есть счетчик ссылок из alloc/init, есть две ссылки, и я принимаю только один выпуск (в вашем деструкторе).

В основном вызов self.editMyObject действительно делает это;

-(void) setEditMyObject:(MyObject*)obj 
{ 
    if (editMyObject) 
    { 
    [editMyObject release]; 
    editMyObject = nil; 
    } 

    editMyObject = [obj retain]; 
} 
+0

, за исключением того, что если 'editMyObject == obj', это может сильно потерпеть неудачу, потому что вы освободите объект (возможно, освободите его), а затем попытаетесь сохранить освобожденный указатель. –

3

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

Вы должны прочитать the Cocoa memory management guide, если вы планируете использовать какао вообще. Это не сложно, как только вы это узнаете, но это то, чему вы должны научиться, или у вас будет много таких проблем.

1

Все остальные уже охватывается, почему это вызывает утечку памяти, так что я буду просто звонить в с тем, как избежать «Темп» переменной и до сих пор предотвратить утечку памяти:

self.editMyObject = [[[MyObject alloc] init] autorelease]; 

Это оставит ваш (сохранить) как единственного владельца нового объекта. Точно такой же результат, как и ваш второй пример, но без временного объекта.

+0

В настольном приложении я обычно делаю это. Тем не менее, на iPhone (или в любой среде с ограниченной памятью) использование autorelease может привести к неправильному использованию памяти. Stick с сохранением/выпуском, если вам не нужна автореферат. –

+0

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

+0

Я не знаю деталей, но это хорошо документировано, что автореферат - довольно дорогой звонок на iPhone. – 4thSpace

4

По соглашению в какао и какао-прикосновении любой объект, созданный с использованием [[SomeClass alloc] initX] или [SomeClass newX], создается с сохранением количества единиц. Вы отвечаете за вызов [someClassInstance release], когда вы закончили свой новый экземпляр, как правило, в вашем методе dealloc.

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

В вашем примере, вы, вероятно, это в вашем файле .h:

@property (retain) MyObject *editMyObject; 

Таким образом, в первом примере:

// (2) property setter increments retain count to 2 
self.editMyObject = 

    // (1) new object created with retain count of 1 
    [[MyObject alloc] init]; 

// oops! retain count is now 2 

При создании нового экземпляра MyObject с помощью alloc/init, он имеет счетчик удержания единицы. Когда вы назначаете новый экземпляр self.editMyObject, вы на самом деле вызываете метод -setEditMyObject:, который компилятор создает для вас, когда вы @synthesize editMyObject. Когда компилятор видит self.editMyObject = x, он заменяет его [self setEditMyObject: x].

В вашем втором примере:

MyObject *temp = [[MyObject alloc] init]; 
// (1) new object created with retain count of 1 

self.editMyObject = temp; 
// (2) equivalent to [self setEditMyObject: temp]; 
// increments retain count to 2 

[temp release]; 
// (3) decrements retain count to 1 

вы держите на свой новый объект достаточно долго, чтобы освободить его, так что сохранить счетчик сбалансированный (если вы отпустите его в методе dealloc).

Смотрите также Cocoa strategy for pointer/memory management

0

Было решено и разъяснено, что ниже код не имеет утечки (при условии, @property сохранить и @synthesize для editMyObject):

//does not create memory leak 
MyObject *temp = [[MyObject alloc] init]; 
self.editMyObject = tempt; 
[temp release]; 

Вопрос: ничего плохого со следующим кодом, который не использует указатель temp?

//does not create memory leak ? 
self.editMyObject = [[MyObject alloc] init]; 
[editMyObject release]; 

Для меня это выглядит нормально.

+0

вам необходимо убедиться, что в вашем методе dealloc также выпущен объект: [editMyObject release] или self.editMyObject = nil; – jyavenard

Смежные вопросы