2009-04-16 1 views
2

Я знаю, что если вы сделаете следующее вы, безусловно, имеет место утечка памяти:Это утечка памяти объектива-c?

id foo = [[NSObject alloc] init]; 
foo = nil; 

Но что, если вы используете self.foo, свойство с сохранить? И ваш код вместо выглядит следующим образом:

foo = [[NSObject alloc] init]; 
self.foo = nil; 

Это еще утечка памяти, поскольку аксессор освобождает память, прежде чем установить его в ноль?

ответ

4

self.foo = nil воплотится в

[nil retain] 
[foo release] 
foo = nil 

Там нет утечки памяти здесь.

2

Нет, второй пример не является утечкой памяти. Фактически, именно так я общаюсь с retain свойствами в моем методе dealloc. Это намного чище.

Единственное, что вы должны быть осторожны, о убедившись, что не писать

self.foo = [[NSObject alloc] init]; 

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

+4

Помните, что использование свойств в dealloc обычно обескураживается в случае изменения метода доступа для изменения другого ivar (который уже мог быть выпущен). Вместо этого я использую release. –

+0

@Alex: +1 за отличное предупреждение, но -1 за предложение использовать self.foo = nil в методе dealloc! –

+2

@eJames self.foo = nil - это то, как Apple рекомендовала делать это в методе dealloc изначально и повсюду в своем примере кода. –

0

Я не думаю, что, делая self.foo = nil, вы по существу используете сеттер и получаете управление памятью бесплатно.

1

Свойства делают ваш код похожим на присвоение, но на самом деле они такие же, как традиционные методы доступа, которые вы могли бы написать себе до Obj-C 2.0. С объектами Obj-C просто генерирует методы доступа за кулисами вместо вас, используя ключевые слова, указанные вами в объявлении (при условии, что вы используете @synthesize и не записываете свои собственные методы доступа в любом случае).

1

Нет, утечки памяти нет. Код в вашем втором примере логически эквивалентно

foo = [[NSObject alloc] init]; 
[nil retain]; 
[foo release]; 
foo = nil; 

потому что @synthesized сеттер logicall эквивалентно

- (void)setFoo:(id)newFoo { 
    [newFoo retain]; 
    [foo release]; 
    foo = newFoo; 
} 

Стоит отметить, что установка foo непосредственно, вероятно, не то, что вы хотите сделать снаружи метод init. Если вы присвоите значение foo напрямую, вы обходите автоматическое уведомление KVO (вам нужно было бы обернуть ваше задание в пару willChangeValueForKey:/didChangeValueForKey:) и вы нарушаете поведение любого подкласса, если оно переопределяет метод setFoo:, ожидая всех изменений foo пройти через сеттер.

Вы назначаете непосредственно foo в методе инициализации, так как метод setFoo: или подкласс перекрываться setFoo: метод может иметь побочные эффекты или зависят от экземпляра полностью инициализирован.

Аналогичным образом, по методу [foo release] вы использовали бы self.foo = nil; по методу -dealloc.

1

Все ответы до сих пор предполагают, что «foo» в первой строке второго примера является переменной экземпляра за свойством foo.Это поведение по умолчанию.

Если foo, присвоенный первой строкой, является локальной переменной, то свойство foo не имеет значения, и вы будете утечка объекта, если вы не отпустите его позже в методе.

Если foo является переменной экземпляра, но свойство foo на самом деле поддерживается другой переменной экземпляра или вообще не имеет переменной экземпляра, то (а) вы пишете жесткий код для сохранения и (b) он может быть утечкой.

Наконец, повторяя предыдущие ответы: Если foo переменная экземпляра, поддержав foo свойство, то это не утечка, так как метод setFoo:, что вы звоните во второй строке будет освободить объект, который вы положили в foo переменная экземпляра в первой строке.

0

Поскольку никто, похоже, не заметил: Там может быть утечка.

я буду считать, что foo является как Ивар и retain свойство:

@interface Foo : NSObject { 
    NSObject * foo; 
} 
@property (nonatomic, retain) NSObject * foo; 
@end 

Допустим, ваш код выглядит примерно так:

-(void)bar { 
    foo = [[NSObject alloc] init]; 
    self.foo = nil; 
} 

Это само по себе не просочиться предоставлено foo было нуль, чтобы начать с. Это не означает, что она не будет течь - скажем, вы добавить еще код:

-(void)baz { 
    self.foo = [[NSObject new] autorelease]; 
} 

-(void)fubar { 
    [self baz]; 
    [self bar]; 
} 

Такие вещи, как foo = [[Foo alloc] init] вообще безопасен в init -методов, потому что предполагается, что вы только позвонить по одному из них, так что foo является гарантированно будет nil изначально. В другом месте вы должны быть немного осторожнее.

// Use assertions so it crashes debug builds if it's already set 
assert(!foo); 
foo = [[NSObject alloc] init]; 
self.foo = nil; 

// Or release explicitly. 
[foo release]; 
foo = [[NSObject alloc] init]; 
self.foo = nil; 

// Or just use the setter, which will do the "right thing". 
// This is particularly relevant for "copy" or "assign" accessors. 
self.foo = [[[NSObject alloc] init] autorelease]; 
self.foo = nil; 

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

  • Нет связанных вопросов^_^