Шрифт:
Примечание. В практике надежного программирования не принято замещать метод alloc, поскольку он работает с физическим местоположением в памяти. Не следует вмешиваться в работу системы на этом уровне.
Объявление static для переменной gCounter делает ее доступной для любого метода, определенного в секции implementation, но при этом она недоступна вне этого файла. Метод allocF просто наращивает значение переменной gCounter и затем использует метод alloc для создания новой дроби (Fraction), возвращая результат. Метод count просто возвращает значение счетчика (gCounter), не давая пользователю непосредственный доступ к этой переменной.
Напомним, что объявления extern не требуются в этих методах, поскольку переменная gCounter определена внутри этого файла. Это просто помогает читателю метода понять, что выполняется доступ к переменной, определенной вне метода. Префикс g в имени переменной предназначен для той же цели, поэтому большинство программистов обычно не включают объявления extern. В программе Ю.2 выполняется тестирование этих методов. #import "Fraction.h" int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *a, *b, *c; NSLog (@"Fractions allocated: %i", [Fraction count]); a = [[Fraction allocF] init]; b = [[Fraction allocF] init]; c = [[Fraction allocF] init]; NSLog (@"Fractions allocated: %i", [Fraction count]); [a release]; [b release]; [c release]; [pool drain]; return 0; }
Вывод программы 10.2 Fractions allocated: 0 (Выделено объектов Fraction) Fractions allocated: 3
Когда начинается выполнение этой программы, значение gCounter автоматически задается равным 0 (напомним, что вы можете замещать наследуемый метод инициализации класса, если хотите выполнить специальную инициализацию класса в целом, например, присвоить статическим переменным некоторые ненулевые значения). После выделения (и последующей инициализации) трех объектов типа Fraction с помощью метода allocF метод count считывает переменную counter, значение которой действительно стало равным 3. Вы можете добавить метод-установщик (setter) для этого класса, если хотите выполнять сброс счетчика или задавать для него определенное значение, но в данном случае это не требуется. 10.3. Описатели хранения для класса
Вы уже познакомились с описателями хранения для класса, которые можно помещать перед именами переменных. Здесь мы рассмотрим другие описатели, которые предоставляют компилятору информацию о предполагаемом использовании переменной в программе. auto
Это ключевое слово используется для объявления автоматической локальной переменной (в противоположность статической). Это описатель по умолчанию для объявления переменной внутри функции или метода, но никто не использует его в явном виде. auto int index;
Это объявление переменной index как автоматической локальной переменной; это означает, что для нее выполняется автоматическое выделение памяти при входе в блок (которым может быть заключенная в фигурные скобки последовательность операторов, метод или функция) и автоматическое освобождение при выходе из этого блока. Поскольку это происходит по умолчанию внутри блока, оператор int index;
эквивалентен оператору auto int index;
В отличие от статических переменных, которые имеют по умолчанию начальные значения 0, автоматические переменные остаются неопределенными, пока вы не присвоите им значения в явном виде. const
Компилятор позволяет связывать атрибут const с переменными, значения которых не будут изменяться. Иначе говоря, он сообщает компилятору, что указанные переменные имеют постоянное значение при выполнении программы. Если попытаться присвоить значение переменной, объявленной с атрибутом const, после инициализации, или попытаться выполнить ее наращивание или уменьшение, компилятор выдаст предупреждающее сообщение. Ниже в переменной pi используется атрибут const: const double pi = 3.141592654;
Он указывает компилятору, что программа не будет изменять эту переменную. Естественно, значение такой переменной должно быть инициализировано при ее определении.
Определение переменной с атрибутом const указывает читателю, что программа не будет изменять значение этой переменной. volatile
Это описатель, противоположный const. Он в явном виде указывает компилятору, что соответствующая переменная будет изменять свое значение. Он включен в язык Objective-C, чтобы компилятор не оптимизировал операторы, которые кажутся избыточными, и выполнял повторную проверку переменной, когда ее значение, казалось бы, не изменяется. Типичный пример — порт ввода-вывода, (I/O) (подробнее см. главу 13).
Предположим, что у вас имеется адрес выходного порта, хранящегося в программе в переменной с именем outPort. Записать в этот порт два символа, например 0 и N, можно с помощью следующего кода. *outPort = 'O’; *outPort = ’N’;
В первой строке указывается, что символ 0 нужно сохранить по адресу памяти, указанному переменной outPort. Во второй строке указывается, что символ N нужно сохранить по тому же адресу. Оптимизирующий компилятор может заметить, что это две последовательные записи по одному адресу, и поскольку outPort между ними не изменяется, может просто удалить первый оператор из программы. Чтобы этого не произошло, нужно объявить переменную outPort с атрибутом volatile, например: volatile char *outPort; 10.4. Перечислимые типы данных