Это утечка памяти в объективе c? - PullRequest
2 голосов
/ 16 апреля 2009

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

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

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

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

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

Ответы [ 7 ]

4 голосов
/ 16 апреля 2009

self.foo = nil будет переводиться в

[nil retain]
[foo release]
foo = nil

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

2 голосов
/ 16 апреля 2009

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

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

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

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

1 голос
/ 16 апреля 2009

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

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

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

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

1 голос
/ 16 апреля 2009

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

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

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

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

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

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

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

1 голос
/ 16 апреля 2009

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

0 голосов
/ 01 декабря 2010

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

Я предполагаю, что foo является одновременно свойством ivar и 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;
0 голосов
/ 16 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...