Программирование на Objective-C 2.0
Шрифт:
Если вы решили использовать сборку мусора, то должны включить ее при создании программ с помощью Xcode. Это можно делать через меню Project (Проект), Edit Project Settings (Изменение настроек проекта). В настройках «GCC 4.0-Code Generation» вы увидите пункт Objective-C Garbage Collection (Сборка мусора Objective-C). Измените ее со значения по умолчанию Unsupported (Не поддерживается) на Required (Требуется), чтобы ваша программа создавалась с включением автоматической сборки мусора (см. рис. 17.1).
Рис. 17.1. Включение сборки мусора
С включенной сборкой мусора в программе могут по-прежнему использо-ваться вызовы методов retain, autorelease, release и dealloc. Однако все они будут игнорироваться.
Примечание. Способы управления памятью, описанные в этой главе, достаточны для большинства приложений. Однако в более сложных случаях, например, при написании многопотоковых приложений, могут потребоваться дополнительные сведения. О вопросах, относящихся к сборке мусора, см. приложение D. Упражнения
Напишите программу, чтобы проверить, как влияет добавление и удаление зап исей в словарь на счетчик ссылок объектов, которые вы добавляете и удаляете.
Как, по вашему мнению, будет влиять метод NSArray replaceObjectAtlndex:withObject: на счетчик ссылок объекта, который заменяется в массиве? Напишите соответствующую программу для проверки. Затем ознакомьтесь с документацией по этому методу, чтобы проверить результаты.
Вернемся к классу Fraction, с которым мы работали на протяжении части I этой книги. Для вашего удобства он приводится в приложении D. Внесите изменения в этот класс, чтобы работать в Foundation framework. Затем добавьте нужные сообщения в различные методы категории MathOps, чтобы добавлять в autorelease-пул дроби (fraction), получаемые в результате каждой операции. Сможете ли вы использовать после этого следующий оператор без утечки памяти? [[fractionA add: fractionB] print]; Объясните ответ.
Вернемся к примерам AddressBook и AddressCard из главы 15. Внесите измене-ния в каждый метод dealloc, чтобы выводить сообщение при вызове метода. Затем выполните некоторые примеры программ, где используются эти классы, чтобы убедиться, что сообщение dealloc передается каждому объекту AddressBook и AddressCard, прежде чем будет достигнут конец main.
Выберите любые две программы из этой книги и выполните их в Xcode с включенной сборкой мусора. Убедитесь, что в этом случае игнорируются вызовы таких методов, как retain, autorelease и release.
Глава 18. Копирование объектов
В этой главе рассматриваются некоторые особенности копирования объектов. Мы рассмотрим понятия поверхностного (shallow) и глубокого (deep) копирования и опишем, как создавать копии в Foundation framework.
В главе 8 было показазно, что происходит, если мы присваиваем один объект другому с помощью простого оператора присваивания, например origin = pt;
В этом примере origin и pt — это объекты класса XYPoint, которые определены следующим образом. @interface XYPoint: NSObject { intx; int у; @end
Напомним, что присваивание — это просто копирование адреса объекта pt в origin. После операции присваивания обе переменные указывают одно и то же место в памяти. Внесение изменений в переменные экземпляра с помощью сообщения [origin setX: 100 andY: 200];
приводит к изменению координат х,у объекта класса XYPoint. на который ссыла-ются обе переменные (origin и pt), поскольку они указывают на один и тот же объект в памяти.
То же самое относится к объектам Foundation: присваивание одной перемен-ной другой вызывает создание еще одной ссылки на объект (но приводит к нара-щиванию счетчика ссылок, см. главу 17). Например, если dataArray и dataArray2 — объекты класса NSMutableArray, то следующие операторы удаляют первый элемент из одного и того же массива, на который ссылаются обе эти переменные. dataArray2 = dataArray; [dataArray2 removeObjectAtlndex: 0]; 18.1. Методы copy и mutableCopy
В классах Foundation реализованы методы сору и mutableCopy, предназначенные для создания копии объекта. Для создания копий методы реализуются в соот-ветствии с протоколом . Если для вашего класса требуется различать создание мутабельных и немутабельных копий объекта, то методы реализуются согласно протоколу .
Вернемся к методам копирования в классах Foundation для двух объектов dataArray2 и dataArray класса NSMutableArray. С помощью
оператора dataArray2 = [dataArray mutableCopy];создается новая копия массива dataArray в памяти с дублированием всех его эле-ментов. Поэтому оператор [dataArray2 removeObjectAtlndex: 0];
удаляет первый элемент из массива dataArray2, но не из массива dataArray.
Это показано в программе 18.1. #import <Foundation/NSObject.h> #import <Foundation/NSArray.ti> #import <Foundation/NSString.h> ffimport <Foundation/NSAutoreleasePool.h> int main {int arge, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSMutableArray *dataArray = [NSMutableArray arrayWithObjects: @none'', @"two", @"three", @"four", nil]; NSMutableArray *dataArray2; // простое присваивание dataArray2 = dataArray; [dataArray2 removeObjectAtlndex: 0]; NSLog (@"dataArray:"); for ( NSString *elem in dataArray ) NSLog (@" elem); NSLog (@"dataArray2:"); for ( NSString *elem in dataArray2 ) NSLog (@n elem); // копирование, затем удаление первого элемента из копии dataArray2 = [dataArray mutableCopy]; [dataArray2 removeObjectAtlndex: 0]; NSLog {@"dataArray: for ( NSString *elem in dataArray ) NSLog (@n %@\ elem); NSLog (@"dataArray2: "); for ( NSString *elem in dataArray2 ) NSLog (@" %@", elem); [dataArray2 release]; [pool drain]; return 0; }
Вывод программы 18.1 dataArray: two three four dataArray2: two three four dataArray: two three four dataArray2: three four `` В программе определяется объект мутабельного массива dataArray, и его эле-ментам присваиваются строковые объекты @"one", @"two", @"three", @"four" соответственно. Как говорилось выше, оператор присваивания
dataArray2 = dataArray; просто создает еще одну ссылку на тот же объект массива в памяти. Поэтому после удаления первого объекта из dataArray2 и вывода элементов объектов-мас-сивов первый элемент (строка @''опе") исчезает из обеих ссылок на этот объект-массив. Затем мы создаем мутабельную копию dataArray и присваиваем полученную копию массиву dataArray2. В результате получаются два отдельных мутабельных массива в памяти, каждый из которых содержит три элемента. Теперь удаление первого элемента из dataArray2 не оказывает влияния на содержимое массива dataArray, что подтверждается последними двумя строками вывода программы. Отметим, что для создания мутабельной копии объекта копируемый объект не обязан бытьмутабельным. То же относится и кнемутабельным копиям: можно сделать немутабельную копию мутабельного объекта. При создании копии массива операция копирования автоматически наращивает счетчик ссылок (удержаний) для каждого элемента массива. Поэтому после создания копии массива и последующего высвобождения (release) исходного массива элементы копии продолжают действовать. Но поскольку копия массива dataArray была создана в этой программе с по-мощью метода mutableCopy, вы обязаны сами освободить его память. Как расска-зывалось в предыдущей главе, вы обязаны сами высвобождать объекты, которые создали с помощью одного из методов копирования, поэтому в конце программы 18.1 вставлена строка
[dataArray2 release]; ## 18.2. Поверхностное и глубокое копирование В программе 18.1 элементы массива dataArray заполняются немутабельными стро-ками (напомним, что константные строковые объекты яатяютси немутабельными). В программе 18.2 мы будем заполнять его мутабельными строками, чтобы можно было изменить одну из арок в этом массиве. Просмотрите программу 18.2 и постарайтесь понять ее вывод. import ffimport import import
int main (int arge, char argv[]) { NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init]; NSMutableArray dataArray = [NSMutableArray arrayWithObjects: [NSMutableString stringWithString: @"one"], [NSMutableString stringWithString: @"two"], [NSMutableString stringWithString: @"three"], nil ]; NSMutableArray dataArray2; NSMutableString mStr; NSLog (@"dataArray:"); for ( NSString elem in dataArray ) NSLog {@" %@", elem); // создание копии, затем изменение одной из строк dataArray2 = [dataArray mutableCopy]; mStr = [dataArray objectAtlndex: 0]; [mStr appendString: @"ONE"]; NSLog (@"dataArray: for ( NSString elem in dataArray ) NSLog (@" %@", elem); NSLog (@"dataArray2: "); for ( NSString e!em in dataArray2 ) NSLog (@" %@", elem); [dataArray2 release]; [pool drain]; return 0; } Вывод программы 18.2