Интернет магазин китайских планшетных компьютеров |
|
Компьютеры - Objective-C - Управление памятью06 июля 2011Оглавление: 1. Objective-C 2. Синтаксис языка 3. Создание новых классов 4. Как работает механизм сообщений 5. Протоколы 6. Обработка исключений 7. Создание и уничтожение объектов 8. Управление памятью 9. Категории 10. Class objects и Objective-C runtime 11. Разное Базовые принципыУправление памятью в Objective C базируется на принципе "владения объектом". Основные правила управления памятью в Objective C можно записать так:
Данные правила базируются на соглашении по именованию в Objective C и, в то же время, сами являются основой этого соглашения. Базовые принципы на практикеПредположим, в программе существует класс Company, у которого есть метод workers. @interface Company : NSObject { NSArray *workers; } -workers; @end Рассмотрим небольшой пример использования такого класса: Company *company = init]; // ... NSArray *workers = ; // ... ; Так как объект класса Company создается явно, он должен быть удален по окончании использования. В то же время, название метода workers не говорит о том, кто должен удалять массив. В такой ситуации считается, что списком работников управляет объект Компания и его удалять не требуется.
Многие классы позволяют совместить создание объекта с его инициализацией при помощи методов, называемых convenience конструкторы; такие методы обычно называются +className... Можно предположить, что вызывающая сторона ответственна за управление временем жизни объекта, но подобное поведение противоречило бы соглашению по именованию в Objective C. Company *company = ; ; В приведенном коде вызов не допустим, т.к. в данном случае управление временем жизни объекта должно осуществляться при помощи autorelease пула. Ниже приводится пример корректной реализации метода company: +company { id ret = init]; return ; }
Вернемся к методу workers класса Company. Так как возвращается массив, временем жизни которого вызывающая сторона не управляет, реализация метода workers будет выглядеть приблизительно так: -workers { NSArray *copy = initWithArray:workers]; return ; } Вызов autorelease добавляет объект copy в autorelease пул, вследствие чего возвращаемый объект получит сообщение release при удалении пула, в который он был добавлен. Если объекту, добавленному в autorelease пул, послать сообщение release самостоятельно, при удалении autorelease пула возникнет ошибка.
В ряде случаев объекты возвращаются по ссылке, например, метод класса NSData initWithContentsOfURL:options:error: в качестве параметра error принимаетerrorPtr. В этом случае так же работает соглашение по именованию, из которого следует, что явного запроса на владение объектом нет, соответственно, удалять его не требуется.
Когда счетчик ссылок объекта становится равным нулю, объект удаляется. При этом у объекта вызывается метод -dealloc. Если в объекте содержатся какие-то данные, их необходимо удалить в этой функции. -dealloc { ; ; } После того, как всем переменным класса было послано сообщение release, необходимо вызвать метод dealloc базового класса. Это единственный случай, в котором допустим вызов метода dealloc напрямую. Не существует никаких гарантий относительно времени вызова метода dealloc. В ряде случаев он вообще может не вызываться при завершении работы приложения для экономии времени, т.к. по завершении приложения ОС в любом случае освободит выделенную память. Соответственно, в методе dealloc не должно располагаться никаких методов, отвечающих за закрытие сокетов, файлов и т.п. Autorelease poolAutorelease пул используется для хранения объектов, которым будет послано сообщение release при удалении пула. Для того, чтобы добавить объект в autorelease пул, ему необходимо отправить сообщение autorelease. В приложениях Cocoa autorelease пул всегда доступен по умолчанию. Для не-AppKit приложений необходимо создавать и управлять временем жизни autorelease пула самостоятельно. Autorelease пул реализуется классом NSAutoreleasePool. int main { NSAutoreleasePool * pool = init]; Company *company = ; NSArray *workers = ; ; return 0; } Удалить объекты из autorelease пула можно не только посредством отправки пулу сообщения release, но и с помощью сообщения drain. Поведение release и drain в среде с подсчетом ссылок идентично. Но в случае работы в GC среде drain вызывает функцию objc_collect_if_needed.
В Cocoa для каждого из потоков создается свой собственный autorelease пул. По завершении потока autorelease пул уничтожается и всем содержащимся в нем объектам посылается сообщение release. Autorelease пул главного потока периодически пересоздается с целью уменьшения используемой памяти приложением. Во всех остальных потоках заниматься пересозданием autorelease пула необходимо самостоятельно, что крайне актуально для долгоживущих потоков. Копирование объектовВсе объекты в Objective C потенциально поддерживают копирование. Для того, чтобы создать копию объекта, необходимо вызвать метод copy, определенный в классе NSObject. Для создания копии будет вызван метод copyWithZone интерфейса NSCopying. NSObject не имеет поддержки этого протокола и при необходимости протокол NSCopying должен быть реализован в классах-наследниках. Копии бывают двух видов: легкая копия и полная копия. Разница между этими копиями состоит в том, что при создании легкой копии копируются не данные, а ссылка на объект с данными. В случае полной копии копируется объект с данными.
Реализация копирования может различаться в зависимости от того, поддерживает ли класс-родитель протокол NSCopying. Пример кода для ситуации, когда родитель не реализует протокол NSCopying: @interface Company : NSObject <NSCopying> { NSString *name; } @property NSString *name; -copyWithZone:zone; @end @implementation Company @synthesize name; -copyWithZone:zone { id copy = allocWithZone:zone] init]; ]; return copy; } @end Если родитель поддерживает протокол NSCopying, реализация будет несколько иной: вызов allocWithZone заменяется на copyWithZone. id *copy = ;
Для immutable объектов создание копии нецелесообразно, и можно ограничиться отправкой самому себе сообщения retain. -copyWithZone:zone { return ; } Просмотров: 11396
|