Метод dealloc
никогда не вызывается напрямую. Все делается с помощью механизма retain
/ release
(и принципа подсчета ссылок). Так что вызывается метод release
, а не dealloc
напрямую. Метод dealloc
вызывается средой выполнения только в том случае, если последний вызов release
приводит к тому, что счетчик ссылок (retainCount) объекта достигает нуля, что означает, что объект действительно освобожден из памяти, поскольку никто его больше не использует.
NSArray
и все контейнерные классы в Какао (NSDictionary
, NSSet
, ...) сохраняют свои значения. Поэтому, когда вы добавляете объект в контейнер, такой как NSArray
, он будет retain
это значение. И когда вы удаляете это значение (в том числе при вызове removeAllObjects "), оно будет release
it.
Правилам Memory Mgmt легко следовать, но единственное правило, которое имеет значение, это то, что вам нужно вызывать release
или autorelease
, только если вы вызывали alloc
, retain
или copy
методы. Это всегда ответственность объекта, который сделал alloc
/ retain
/ copy
для вызова release
/ autorelease
. Никогда не оставляйте alloc
/ retain
/ copy
без ожидающего release
/ autorelease
звонка, чтобы сбалансировать его (или у вас будут утечки), но с другой стороны, никогда не звоните release
/ autorelease
если вы не сделали alloc
/ retain
/ copy
, позвоните себе.
Хороший пример 1:
MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[obj release]; // this release balance the "alloc" on the first line, so that's good
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. As nobody retains it anymore, its dealloc method will be called automatically.
Хороший пример 2:
MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. But your own code still retains a reference to it (because of the "alloc" on first line) so it won't be removed from memory right now
[obj release]; // this release balance the "alloc" on the first line, and as nobody retains the object anymore, its dealloc method will be called and it will be deallocated from memory
Хороший пример 3:
MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
// no need to call "release" here as there is no "alloc" done in the scope of this code
Плохой пример:
MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
[obj release]; // Crash here! obj does not exists anymore and has been deallocated from memory before this line!