memory managment in i os
TRANSCRIPT
Управление памятью в iOS -
Лучшие Практики
2
Почему об этом столько говорят?
• Не полностью автоматоматическое• Не полностью ручное
• Нет Garbage Collector под iOS
Подсчёт ссылок•Alloc (+1) 1•Retain (+1) 2•Release (-1) 1•Release (-1) 0•Release ПАДЕНИЕ!
Владение объектом• Кто сделал init, тот и папа
SomeObject *iOwnThis = [[SomeObject alloc] init]; [iOwnThis doYourThing];
[iOwnThis release];
• Временный объектNSNumber* value = [NSNumber numberWithFloat:14.78];
Передача владения
- (void) setName: (NSString*)str {
[name release];
name = [str retain];
}
5
Договорённость по именованию
• Чтобы создать объект и стать его владельцем надо использовать один из следующих методов–alloc–new–copy–mutableCopy
6
dealloc
•Отвечает за освобождение памяти• Внутри нужно вызвать [super dealloc]• Не рекомндуется вкладывать другую
функциональность•Можно сделать [obj release] если obj равен nil• Этот метод нигде кроме [super dealloc] не
должен вызываться вручную
7
Property в Objective C
• Writability–readonly–readwrite
• Setter semantic–assign–copy–retain
• Atomicity–atomic–nonatomic
8
Property
•Обьявление
@property (writability, setter, atomicity) type *name;@synthesize name = _name;
•Использование
object.propertyName = newValue;value = object.propertyName;
9
Assign property- (void)setSomeValue:(SomeVariable*)aSomeVariableValue
{
someValue = aSomeVariableValue;
}
10
Retain property- (void)setSomeInstance:(SomeClass *)aSomeInstanceValue
{
if (someInstance == aSomeInstanceValue)
return;
SomeClass *oldValue = someInstance;
someInstance = [aSomeInstanceValue retain];
[oldValue release];
}
11
Copy property- (void)setStringValue:(NSString *)aString
{
if (stringValue == aString)
return;
NSString *oldValue = stringValue;
stringValue = [aString copy];
[oldValue release];
}
NSAutoreleasePool
• *** __NSAutoreleaseNoPool(): Object autoreleased with no pool in place — just leaking• В других потоках надо создавать отдельно
• В него добавляются временные объекты• Автоматически создаётся в
главном потоке
13
AutoreleasePool в главном потоке
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, nil);
}
}
14
Распространённые ошибки- (void) reset
{
NSNumber * zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
}
Исправленная версия- (void) reset{ NSNumber * zero = [[NSNumber alloc] initWithInteger:0]; [self setCount:zero]; [zero release];}
15
Распространённые ошибки• - (void) reset
• {
• NSNumber * zero = [NSNumber numberWithInteger:0];
• [self setCount:zero];
• [zero release];
• }
•Исправленная версия•
- (void) reset• {• NSNumber * zero = [NSNumber numberWithInteger:0];• [self setCount:zero];• }
16
Возвращение Property• - (NSNumber*) count
• {
• [count retain];
• return count;
• }
•Исправленная версия• - (NSNumber*) count• {• return count;• }
17
Обращение к Property• - (void) reset
• {
• NSNumber * zero = [NSNumber numberWithInteger:0];
•
• self.count = zero;
• //Разные вещи!!!
• count = zero;
• }
18
Добавление в массив передаёт владение объектом
• - (NSArray *)getPeople {
• NSMutableArray *array = [[NSMutableArray alloc] init];
• for (int i = 0; i < 10; i++) {
• Person *p = [[Person alloc] init];
• [array addObject:p];
• }
• return array;
• }
• Исправленная версия
• - (NSArray *)getPeople {
• NSMutableArray *array = [[NSMutableArray alloc] init];
• for (int i = 0; i < 10; i++) {
• Person *p = [[Person alloc] init];
• [array addObject:p];
• [p release];
• }
• return array;
• }
19
Перезапись без release- (void) leak
{
name = [[NSString alloc] initWithFormat:@"%@-%@",@"John",@"Paul"];
name = @"Chris";
}
Исправленная версия- (void) leak
{
name = [[NSString alloc] initWithFormat:@"%@-%@",@"John",@"Paul"];
[name release];
name = @"Chris";
}
20
Повисший указатель- (id) init{
if (self = [super init]) {
count = [NSNumber numberWithInteger:0];
}
return self;
}
- (void) logCount
{
NSLog(@"Count is %@",count);
}
21
Исправленная версия - (id) init{ if (self = [super init]) { count = [NSNumber numberWithInteger:0]; [count retain]; } return self;}
- (void) logCount { NSLog(@"Count is %@",count);}
- (void) dealloc { [count release];}
22
Обнуление делегатов- (void)dealloc
{
self.someObject.delegate = nil;
self.someObject = nil;
[super dealloc];
}
23
Memory Warning
• Автоматически делаетсяsetView:nil неактивным ViewControllers
• Чистим ресурсы в приложении- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[[ImageCache sharedImageCache] removeAllImagesInMemory];
}
• Подписываемся на Notification
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(whatever:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
Устранение ошибок памяти
•Используйте LLVM / Clang статический анализатор•Не overthink управления памятью•Всегда используйте методы доступа; объявить
доступа с использованием свойств•Инструмент Инструменты Утечки
EXC_BAD_ACCESS
• Поставтье брейкпойнт в программе и шагайте до падения• Тактика закомменть и попробуй падает ли• NSZombieEnabled - при падении можно увидеть к
объекту какого типа было обращение и какой селектор был вызван
26
Clang Static Analyzer
27
Автоматический подсчёт ссылок
• По сути - автоматическое исправление всех замечаний найденных статическим анализатором• Не сборка мусора!• Не может решить всех проблем связанных с
циклическими ссылками
28
Property в ARC
• strong - аналог retain. Проперти является владельцем объекта по ссылке•weak - слабая ссылка без владения.
Автоматически ставиться в nil когда объект по ссылке удаляется.• unsafe_unretained - синоним assign. Надо
использовать вместо weak в iOS 4• copy - всё попрежнему, объект копируется и
создаётся сильная связь