Управление политикой памяти

Cocoa

Базовая модель используемая для управления памятью со счетчиком ссылок обеспечивается сочетанием методов, определенных в протоколе NSObject и стандартными методами именования. Класс NSObject также определяет метод dealloc, который вызывается автоматически, когда объект будет освобожден. В этой статье описаны все основные правила, которые вы должны знать, чтобы правильно управлять памятью в Cocoa программах, а также предоставляет примеры правильного использования.

Основные правила управления памятью

Модель управления памятью основывается на владении объектами. Любой объект может иметь одного или несколько владельцев. Пока объект имеет по крайней мере одного владельца, он продолжает существовать. Если объект не имеет владельцев, система уничтожает его автоматически. Чтобы убедиться, что объекты освобождаются, когда у вас есть объект, Cocoa устанавливает следующую политику:

  • Вы владеете каким-либо объектом вами созданным

    Вы можете создать объект, используя метод, имя которого начинается с "alloc", "new", "copy", или "mutableCopy".

  • Вы можете стать владельцем объекта, используя retain

    Полученный объект, как правило, гарантированно остается в силе в течение выполнения метода, в котором он был получен, и этот метод также может безопасно вернуть объект к вызвовшему его методу. Вы используете retain в двух случаях: (1) В реализации метода доступа или инициализации метода, чтобы стать владельцем объекта, который нужно сохранить как значение свойства, (2) Для предотвращения освобождения объекта как побочного эффекта от некоторых других операций

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

    Вы отказываетесь от права собственности на объект, послав ему сообщение release или autorelease сообщение. В Cocoa терминологии, из отказа от права владения объектом, как правило следует, "освобождение" объекта.

  • Вы не должны отказаться от права владения объектом, которого у вас нет

    Это всего лишь следствие предыдущих правил политики, заявиленных в явном виде.

Простой пример

{
    Person *aPerson = [[Person alloc] init];

    // ...

    NSString *name = person.fullName;

    // ...

    [aPerson release];
}

Объект Person создается с помощью метода alloc, так что впоследствии отправлено сообщение release, когда он больше не нужен. Переменная name объекта Person не получалась с помощью одного из захватывающих метода, поэтому ей не будет отправлено сообщение release. Обратите внимание, что пример использует release, а не autorelease.

Используйте autorelease для Отправки отложенного release

Вы можете использовать autorelease, когда вам нужно отправить отложенное сообщение release, обычно при возврате объекта из метода. Например, вы могли бы реализовать FullName метод следующим образом:

- (NSString *)fullName {

    NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
        self.firstName, self.lastName] autorelease];

    return string;
}

Вы владеете строкой, возвращаемой alloc. Чтобы соблюдать правила управления памятью, вы должны отказаться от собственности на строку, прежде чем потерять ссылку на нее. Если вы используете release, строка будет освобождена, еще до возврата (и метод будет возвращать неверный объект). Используя autorelease, Вы подтверждаете, что хотяте отказаться от владения объектом, но вы позволяете вызывающему методу использовать возвращенную строку, пока не освободится.

Кроме того, можно осуществить метод FullName следующим образом:

- (NSString *)fullName {

    NSString *string = [NSString stringWithFormat:@"%@ %@",
       self.firstName, self.lastName];

    return string;
}

В соответствии с основными правилами, вы не владеете строкой, возвращаемой stringWithFormat:, так что можно спокойно вернуть строку из метода.

Для сравнения, следующий пример является неправильным:

- (NSString *)fullName {

    NSString *string = [[NSString alloc] initWithFormat:@"%@ %@",
       self.firstName, self.lastName];

    return string;
}

Согласно соглашению об именах, нет ничего, чтобы обозначить, что вызванный метод FullName владеет возвращаемой строки. Вызывающий метод поэтому не имеет никаких оснований для освобождения возвращаемой строки, таким образом произойдет утечка памяти, выделенной под объект string.

Вы не являетесь владельцем объектов, возвращаемых по ссылке

Некоторые методы в Cocoa указавают, что объект возвращается по ссылке (то есть, они не имеют аргумента типа ClassName ** или id *). Данная закономерность заключается в использовании NSError объекта, который содержит информацию об ошибках, если они происходит, о чем свидетельствуют initWithContentsOfURL:options:error: (NSData) и initWithContentsOfFile:encoding:error: (NSString).

В этих случаях применяются те же правила, как уже было описано. При вызове любого из этих методов, вы не создаете NSError объект, так что вы не являетесь его владельцем. Поэтому нет необходимости, его освобождать, как показано в следующем примере:

NSString *fileName = <#Get a file name#>;

NSError *error = nil;

NSString *string = [[NSString alloc] initWithContentsOfFile:fileName
   encoding:NSUTF8StringEncoding error:&error];

if (string == nil) {

    // Deal with error...
}

// ...

[string release];

Реализация dealloc для отказа от права владения объектами

Класс NSObject определяет метод dealloc, который вызывается автоматически, когда объект не имеет владельцев и его память будет утилизирована, в терминологии Cocoa это называется "освободил" или "освобождена". Роль dealloc метода заключается в освобождении собственной памяти объекта, и распоряжением любыми ресурсами которыми он располагает, в том числе любыми переменными экземпляра объекта, которыми он владеет.

Следующий пример иллюстрирует, как можно реализовать dealloc метод для класса Person:

@interface Person : NSObject {}

@property (retain) NSString *firstName;

@property (retain) NSString *lastName;

@property (assign, readonly) NSString *fullName;

@end

 

@implementation Person

@synthesize firstName=_firstName, lastName=_lastName;

// ...

- (void)dealloc

    [_firstName release];

    [_lastName release];

    [super dealloc];

}

@end

Важно: Вы никогда не должны ссылаться на dealloc метод другого объекта непосредственно.

Вы должны вызвать реализацию суперкласса в конце вашей реализации.

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

Когда приложение завершается,dealloc сообщение не направляется в объекты. Потому что память процесса автоматически очищается при выходе, это более эффективно, чем позволить операционной системе, для очистки ресурсов вызывать все методы управления памятью.

 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac