До Xcode 4.2 управление памятью осуществлялось вручную.
В Java, Ruby, Python управлением памятью занимается сборщик мусора.
В Objective-C тоже есть подобная штука, но она не работает на iPhone, iPad, Mac OS X ниже Leopard.
Сборщика мусора по умолчанию в проекте нет.
Управление памятью вручную.
NSString *name = [NSString alloc];
// вы владеете объектом, если создали его или скопировали - случайно это не происходит
// retainCount = 1 (счетчик ссылок объекта)
[name init];
[anotherObject firstMethod:name];
// retainCount = ?
[name release];
// retainCount = 0
name = nil; // в Objective-C nil-объекты игнорируют посылваемые им сообщения
Возможные проблемы:
- указатель ссылается на объект которого уже нет;
- объект есть, а указателя на него нет - утечка памяти.
alloc, new, copy, retain должны быть согласованы с вызовом метода release.
Оборотная сторона правила если вы не являетесь владельцем объекта, то и не вам его освобождать.
ARC сам создает и заполняет метод dealloc, однако все еще сохраняется возможность самому написать этот метод для управления внешними ресурсами.
Как реализовать деструктор для класса?
How do I know whether the compiler has ARC support enabled?
Как включается/выключается ARC в проекте:
objective c - NSString retain Count - Stack Overflow
objective c - Reusing a NSString variable - does it cause a memory leak? - Stack Overflow
После вызова release значение releaseCount бесполезно и может не соответствовать действительности.
Вообще retainCount довольно таки глючная штука и лучше ее не использовать.
Пример ручного управления памятью (ARC выкл.):
Пример полуавтоматического управления памятью (ARC выкл.):
В этом примере вместо блока:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// ...
[pool drain];
можно было бы воспользоваться альтернативным блоком:
@autoreleasepool
{
// ...
}
Это не совсем хороший пример потому что в главном потоке autorelease пул создается по умолчанию при входе в функцию и освобождается на выходе. Как в режиме MRC, так и в ARC. Поэтому тут можно было опустить создание этого блока. В случае отсутствия текущего пула в стеке (для периферийного потока стек изначально пуст) в консоль будет выведено сообщение об ошибке.
ARC сам создает и заполняет метод dealloc, однако все еще сохраняется возможность самому написать этот метод для управления внешними ресурсами.
Как реализовать деструктор для класса?
How do I know whether the compiler has ARC support enabled?
Как включается/выключается ARC в проекте:
objective c - NSString retain Count - Stack Overflow
objective c - Reusing a NSString variable - does it cause a memory leak? - Stack Overflow
После вызова release значение releaseCount бесполезно и может не соответствовать действительности.
Вообще retainCount довольно таки глючная штука и лучше ее не использовать.
Пример ручного управления памятью (ARC выкл.):
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { NSDate *theMyDate; // nil NSString *theMyString; // nil #if !__has_feature(objc_arc) theMyDate = [NSDate date]; NSLog(@"theMyDate.retainCount = %lu", (unsigned long)[theMyDate retainCount]); // [theMyDate retainCount] == 1 theMyString = [[NSString alloc] initWithFormat:@"Hello, World! Today is %@.", theMyDate]; NSLog(@"theMyString.retainCount = %lu", (unsigned long)[theMyString retainCount]); // [theMyString retainCount] == 1 [theMyString release]; theMyString = nil; [theMyDate release]; theMyDate = nil; theMyDate = [NSDate new]; // NSDate *theMyDate = [[NSDate alloc] init]; NSLog(@"theMyDate.retainCount = %lu", (unsigned long)[theMyDate retainCount]); // [theMyDate retainCount] == 1 [theMyDate release]; theMyDate = nil; #else #endif return 0; }
Пример полуавтоматического управления памятью (ARC выкл.):
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { NSDate *theMyDate; // nil NSString *theMyString; // nil #if !__has_feature(objc_arc) NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; theMyDate = [NSDate date]; // здесь autorelease не нужен потому что не мы создаем объект! NSLog(@"theMyDate.retainCount = %lu", (unsigned long)[theMyDate retainCount]); // [theMyDate retainCount] == 1 theMyString = [[[NSString alloc] initWithFormat:@"Hello, World! Today is %@.", theMyDate] autorelease]; NSLog(@"theMyString.retainCount = %lu", (unsigned long)[theMyString retainCount]); // [theMyString retainCount] == 1 theMyDate = [[NSDate new] autorelease]; // NSDate *theMyDate = [[NSDate alloc] init]; NSLog(@"theMyDate.retainCount = %lu", (unsigned long)[theMyDate retainCount]); // [theMyDate retainCount] == 1 [pool drain]; #else #endif return 0; }
- object - What is autoreleasepool? - Objective-C - Stack Overflow
- Advanced Memory Management Programming Guide: Using Autorelease Pool Blocks
- https://ru.wikipedia.org/wiki/Objective-C#Autorelease_pool
В этом примере вместо блока:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// ...
[pool drain];
можно было бы воспользоваться альтернативным блоком:
@autoreleasepool
{
// ...
}
Это не совсем хороший пример потому что в главном потоке autorelease пул создается по умолчанию при входе в функцию и освобождается на выходе. Как в режиме MRC, так и в ARC. Поэтому тут можно было опустить создание этого блока. В случае отсутствия текущего пула в стеке (для периферийного потока стек изначально пуст) в консоль будет выведено сообщение об ошибке.
Is @autoreleasepool needed in ARC mode? · Issue #1 · gologo13/objective-c-practice
У вас может возникнуть вопрос почему директива autoreleasepool работает в режиме ARC, а NSAutoreleasePool и сообщения autorelease не допустимы.
Не нужно путать ARC со сборщиком мусора. Это разные вещи. ARC осуществляет ручное управление за вас, т.е. сам нижнем уровне оперирует с retain, release, и autorelease. Подробнее...
- Debugging retain counts | Big Nerd Ranch
- A look under ARC’s hood – Episode 3 - Matt Galloway
- Popping a top level autorelease pool