Чтение онлайн

на главную - закладки

Жанры

Программирование на Objective-C 2.0
Шрифт:

Когда объект уже не нужен, мы уменьшаем на I его счетчик ссылок, отправляя сообщение release, как в следующей строке. [myFraction release];

Когда счетчик ссылок объект становится равным 0, система «понимает», что этот объект больше не нужен (поскольку на него нет больше ссылок), и поэтому она освобождает (deallocate) его память. Для этого объекту отправляется со-общение dealloc.

Успешное осуществление этой стратегии требует аккуратности от програм-миста, чтобы счетчик ссылок правильно наращивался и уменьшался во время выполнения программы. Как вы увидите ниже, система выполняет только часть этой работы.

Рассмотрим подсчет ссылок несколько подробнее. Объекту можно отправить сообщение retainCount, чтобы получить его счетчик ссылок (или удержаний, retain). Обычно вы не будете использовать этот метод, но здесь мы рассмотрим его в иллюстративных целях (см. программу 17.1). Отметим, что он возвращает целое без знака (unsigned int) типа NSUInteger. //

Знакомство с подсчетом ссылок #import <Foundation/NSObject.h> #import < Foundation/NSAutoreleasePool.h> #import <Foundation/NSString.h> #import <Foundation/NSArray.h> #import <Foundation/NSValue.h> int main (int arge, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSNumber *mylnt = [NSNumber numberWithlnteger: 100]; NSNumber *mylnt2; NSMutableArray *myArr = [NSMutableArray array]; NSLog (@"mylnt retain count = %lx", (unsigned long) [mylnt retainCount]); [myArr addObject: mylnt]; NSLog (@"after adding to array = %lx", (unsigned long) [mylnt retainCount]); mylnt2 = mylnt; NSLog {@"after asssignment to mylnt2 = %lx’\ (unsigned long) [mylnt retainCount]); [mylnt retain]; NSLog (@"mylnt after retain = %lx", (unsigned long) [mylnt retainCount]); NSLog (@"mylnt2 after retain = %lx", (unsigned long) [mylnt2 retainCount]); [mylnt release]; NSLog (@“after release = %lx") (unsigned long) [mylnt retainCount]); [myArr removeObjectAtlndex: 0]; NSLog (@nafter removal from array = %lx", (unsigned long) [mylnt retainCount]}; [pool drain]; return 0; }

Вывод программы 17.1 mylnt retain count = 1 (счетчик удержаний mylnt) after adding to array = 2 (после добавления в массив) after asssignment to mylnt2 = 2 (после присваивания mylnt2) mylnt after retain = 3 (mylnt после удержания) mylnt2 after retain = 3 (mylnt2 после удержания) after release = 2 (после release) after removal from array = 1 (после удаления из массива)

Объекту NSNumber mylnt присваивается целое значение 100, и вывод показы-вает, что начальное число его удержаний равно 1. Затем этот объект добавляется в массив myArr с помощью метода addObject:. Обратите внимание, что после этого его счетчик ссылок равен 2. Метод addObject: делает это автоматически; в документации по addObject: описан этот факт. Добавление объекта в любой тип коллекции увеличивает его счетчик ссылок. Это означает, что когда мы высво-бождаем (release) добавленный ранее объект, на него можно будет по-прежнему ссылаться из массива, и он не будет высвобожден.

Затем мы присваиваем mylnt переменной mylnt2. Отметим, что это не приво-дит к наращиванию счетчика ссылок, что может вызвать в дальнейшем потен-циальные проблемы. Например, если счетчик ссылок для mylnt уменьшится до 0 и его память будет освобождена, mylnt2 будет содержать неверную ссылку на объект (напомним, что присваивание mylnt переменной mylnt2 не приводит к копированию самою объекта, а только к созданию указателя на место в памяти, где находится сам объект).

Поскольку mylnt теперь имеет еще одну ссылку (через mylnt2), мы наращиваем его счетчик ссылок, отправляя ему сообщение retain. Это происходит в следующей сгроке программы 17.1. Как мы видим, после отправки сообщения retain счетчик ссылок становится равным 3. Первая ссылка — это сам объект, вторая ссылка делается из массива и третья — во время присваивания. Сохранение элемента в массиве вызывает автоматическое наращивание счетчика ссылок, а присваивание другому элементу — нет, поэтому мы должны сделать это сами. Отметим, что при выводе счетчик ссылок mylnt и на mylnrt2 дает одинаковое значение 3; дело в том, что в обоих случаях это ссылка на один и тот же объект в памяти.

Предположим, что мы прекратили использовать объект mylnt в программе. Это можно сообщить системе, отправив объекту сообщение release. Как мы можем видеть, его счетчик ссылок в результате уменьшается с 3 до 2. Счетчик нс равен 0; это означает, что продолжают действовать другие ссылки (из массива и через mylnt2). Система не освобождает память, используемую этим объектом, поскольку счетчик ссылок не равен нулю.

После удаления первого элемента из массива myArr с помощью метода removeObjectAtlndex: мы видим, что счетчик ссылок автоматически уменьшился до В общем случае удаление объекта из любой коллекции сопровождается уменьшением на 1 его счетчика ссылок. Поэтому следующая последовательность кода может вызвать проблемы. mylnt = [myArr ObjectAtlndex: 0]; [myArr removeObjectAtlndex: 0]

Дело в том, что в данном случае объект, на который ссылается mylnt, может стать недействительным после вызова метода removeObjectAtlndex:, если его счет-чик ссылок уменьшился до 0. Конечно, для решения этой проблемы нужно удер-жать (retain) mylnt после считывания из массива, чтобы на его ссылку не повлияло то, что происходит в других местах. Подсчет ссылок и строки

В программе 17.2 показано, как действует подсчет ссылок для строковых объектов. // Подсчет ссылок в случае строковых объектов. #import <Foundatton/NSObject.h> #import <Foundation/NSAutoreleasePool.h> Simport <Foundation/NSString.h> #import <Foundation/N$Array.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSString *myStr1 = @"Constant string"; NSString *myStr2 = [NSString stringWithString: @"string 2"]; NSMutableString *myStr3 = [NSMutableString stringWithString: @"string 3"]; NSMutableArray *myArr = [NSMutableArray array]; NSLog (@"Retain count: myStrl: %lx, myStr2: %lx, myStr3: %lx", (unsigned long) [myStrl retainCount], (unsigned long) [myStr2 retainCount], (unsigned long) [myStr3 retainCount]); [myArr addObject: myStrl]; [myArr addObject: myStr2]; [myArr addObject: myStr3]; NSLog (@"Retain count: myStrl: %lx, myStr2: %lx, myStr3: %lx", (unsigned long) [myStrl retainCount], (unsigned long) [myStr2retainCount], (unsigned long) [myStr3 retainCount]); [myArr addObject: myStrl]; [myArr addObject: myStr2]; [myArr addObject: myStr3]; NSLog (@"Retain count: myStrl: %lx, myStr2: %lx, myStr3: %lx", (unsigned long) [myStrl retainCount], (unsigned long) [myStr2retainCount], (unsigned long) [myStr3 retainCount]); [myStrl retain]; [myStr2 retain]; [myStr3 retain]; NSLog (@"Retain count: myStrl: %lx, myStr2: %lx, myStr3: %lx", (unsigned long) [myStrl retainCount], (unsigned long) [myStr2 retainCount], (unsigned long) [myStr3 retainCount]); //

Уменьшение счетчика ссыпок myStr3 снова до 2 [myStr3 release]; [pool drain]; return 0; }

Вывод программы 17.2 Retain count: myStrl: ffffffff, myStr2: ffffffff, myStr3: 1 (Счетчик ссылок:) Retain count: myStrl: ffffffff, myStr2: ffffffff, myStr3: 2 Retain count: myStrl: ffffffff, myStr2: ffffffff, myStr3: 3

Объекту NSString myStrl присваивается строка NSConstantString @'Constant string" (Константная строка). Вьшеление места в памяти для константных строк отличается от других объектов. Константные строки не имеют механизма подсчета ссылок, поскольку их нельзя высвободить. Именно поэтому при отправке сообщения retainCount переменной myStrl счетчик возвращает значение Oxffffffff. (Это на самом деле максимально возможное целое значение без знака, то есть UINT_MAX в стандартном header-файле <limits.h>.)

Примечание. Очевидно, что в некоторых системах счетчик ссылок, возвращаемый для константных строк в программе 17.2, дает значение Qx7fffffif (а не Gxffffffff), что является максимально возможным целым значением со знаком, то есть INT_MAX.

Отметим, что то же самое относится к немутабельному строковому объекту, который инициализируется с константной строкой: он тоже не имеет счетчика ссылок, что подтверждается счетчиком ссылок, выведенным для myStr2.

Примечание. В данном случае система уже достаточно «сообразительна», по-этому она определила, что немутабельный строковый объект инициализируется с помощью константного строкового объекта. До выпуска Leopard такая оп-тимизация не выполнялась, и поэтому для mystr2 действовал счетчикудержаний.

В операторе NSMutableString *myStr3 = [NSMutableString stringWithString: @"string 3"];

переменной myStr3 присваивается строка, полученная из копии константной символьной строки @"string 3". Мы создали копию этой строки, поскольку классу NSMutableString было передано сообщение stringWithString:, указывающее, что содержимое строки может быть изменено в ходе выполнения программы. А по-скольку содержимое константных символьных строк нельзя изменить, система не может сделать так, чтобы переменная myStr3 только указывала на константную строку @"string 3", как это было сделано в случае myStr2.

Поэтому строковый объект myStr3 действительно имеет счетчик ссылок, что подтверждается результатами вывода. Счетчик ссылок можно изменить путем добавления этой строки к массиву или передачи ему сообщения retain, что под-тверждается результатами вывода с помощью последних двух вызовов NSLog. Метод Foundation stringWithString: добавил этот объект в autorelease-пул при его создании. Метод Foundation array также добавил массив myArr в этот пул.

Прежде чем высвободить сам autorelease-пул, высвобождается myStr3. В ре-зультате его счетчик ссылок уменьшается до 2. Высвобождение autorelease-пула уменьшает счетчик ссылок этого объекта до 0, что приводит к освобождению занятой им памяти. Как это происходит? При высвобождении autorelease-пула каждый из объектов этого пула получает сообщение release, и это сообщение передается объекту столько раз, сколько было передано сообщений airtorelease. Поскольку строковый объект myStr3 был добавлен в autorelease-пул при создании этого объекта с помощью метода stringWithString:, ему передается сообщение release. Это уменьшает его счетчик ссылок до 1. При высвобождении массива в autorelease-пуле также происходит высвобождение каждого из его элементов. Поэтому при высвобождении массива туАл из пула каждому из его элементов (включая myStr3) передается сообщение release. "Эго уменьшает его счетчик ссы-лок до 0, в результате чего его память должна быть освобождена.

Поделиться:
Популярные книги

Солнечный корт

Сакавич Нора
4. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Солнечный корт

Отверженный. Дилогия

Опсокополос Алексис
Отверженный
Фантастика:
фэнтези
7.51
рейтинг книги
Отверженный. Дилогия

Хозяин Теней 6

Петров Максим Николаевич
6. Безбожник
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Хозяин Теней 6

Герой

Мазин Александр Владимирович
4. Варяг
Фантастика:
альтернативная история
9.10
рейтинг книги
Герой

Жизнь в подарок

Седой Василий
2. Калейдоскоп
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Жизнь в подарок

Цикл романов "Целитель". Компиляция. Книги 1-17

Большаков Валерий Петрович
Целитель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цикл романов Целитель. Компиляция. Книги 1-17

Имперец. Том 3

Романов Михаил Яковлевич
2. Имперец
Фантастика:
боевая фантастика
попаданцы
альтернативная история
7.43
рейтинг книги
Имперец. Том 3

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Мастер 4

Чащин Валерий
4. Мастер
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Мастер 4

Надуй щеки!

Вишневский Сергей Викторович
1. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки!

Неудержимый. Книга XXVIII

Боярский Андрей
28. Неудержимый
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXVIII

Ученик. Книга третья

Первухин Андрей Евгеньевич
3. Ученик
Фантастика:
фэнтези
7.64
рейтинг книги
Ученик. Книга третья

Газлайтер. Том 17

Володин Григорий Григорьевич
17. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 17

Вернувшийся: Корпорация. Том III

Vector
3. Вернувшийся
Фантастика:
космическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Вернувшийся: Корпорация. Том III