Вход/Регистрация
Программирование на Objective-C 2.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, в результате чего его память должна быть освобождена.

Следите, чтобы не было лишних высвобождений объекта. Если в программе 17.2 сделать счетчик ссылок mystr3 меньше 2 до высвобождения самого пула, то пул будет содержать ссылку на неверный объект. Затем при высвобождении самого пула ссылка на неверный объект вызовет, скорее всего, аварийное за-вершение программы с ошибкой неверной сегментации (segmentation fault). Подсчет ссылок и переменные экземпляра

Счетчикам ссылок необходимо уделять внимание при работе с переменными экземпляра. Вспомним метод setName: из класса AddressCard. -(void) setName: (NSString *) theName { [name release]; name = [[NSString alloc] initWithString: theName]; }

Предположим, что вместо этого мы определили setName: следующим образом и он не получил владения своим объектом name. -(void) setName: (NSString *) theName ( name = theName; }

Эта версия метода получает строку, представляющую имя человека, и со-храняет ее в переменной экземпляра name. Казалось бы, здесь все очевидно, но рассмотрим следующий вызов метода. NSString *newName; [myCard setName: newName];

Предположим, что newName — это пространство временного хранения для имени человека, которого добавили в адресную карточку, и что в дальнейшем эго пространство нужно освободить. Как вы думаете, что произойдет с переменной экземпляра name в myCard? Ее поле name будет недействительным, поскольку будет ссылаться на объект, который был ликвидирован. Именно поэтому нужно, чтобы наши классы имели свои собственные объекты-члены: эти объекты могут быть неожиданно высвобождены или модифицированы.

В следующих примерах этот вопрос обсуждается более подробно. Начнем с определения нового класса ClassA, содержащего одну переменную экземпляра: строковый объект с именем str. Напишем метод-установщик и метод-получатель (setter и getter) для этой переменной. Мы не будем синтезировать эти методы, а напишем их сами, чтобы было ясно, что происходит. // Знакомство с подсчетом ссылок #import <Foundation/NSObject.h> #import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSString.h> @interface ClassA: NSObject { NSString *str; } -(void) setStr: (NSString *) s; -(NSString *) sir; @end @implementation ClassA -(void) setStr: (NSString *) s { str = s; } -{NSString *) str { return str; } @end int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSMutableString *myStr = [NSMutableString stringWithString: @"A string"]; ClassA *myA = [[ClassA alloc] init]; NSLog (@nmyStr retain count: %x", [myStr retainCount]); [myA setStr: myStr]; NSLog (@"myStr retain count: %x", [myStr retainCount]); [myA release]; [pool drain]; return 0; }

Вывод программы 17.3 myStr retain count: 1 (счетчик ссылок myStr) myStr retain count: 1

Программа просто выделяет память (alloc) для объекта класса ClassA с именем myA и затем вызывает метод-установщик (setStr), чтобы присвоить ему объект NSString, указанный myStr. Счетчик ссылок для myStr равен 1 как до, так и после вызова метода setStr (как и следовало ожидать), поскольку этот метод просто сохраняет значение своего аргумента а своей переменной str. И здесь снова, если программа высвободит myStr после вызова метода setStr, значение, сохраненное внутри переменной экземпляра str, будет неверным, поскольку ее счетчик ссылок будет уменьшен до 0 и пространство памяти, занятое объектом, на который она ссылается, будет освобождено.

  • Читать дальше
  • 1
  • ...
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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