Программирование на Objective-C 2.0
Шрифт:
@package. Для 64-битных образов доступ к переменной экземпляра может выполняться в любом месте образа, который реализует данный класс.
Если вам нужно определить класс с именем Printer, содержащий две частные переменные экземпляра с именами pageCount и tonerLevel, которые доступны только методам из класса Printer, то вы можете использовать следующую секцию interface. @interface Printer: NSObject { @ private int pageCount; int tonerLevel; @ protected // другие переменные экземпляра } @end
Доступ к этим двум переменным экземпляра нельзя выполнить из любого подкласса класса Printer, поскольку они сделаны
Эти специальные директивы действуют как переключатели: все переменные, которые появляются после одной из этих директив (пока не появится правая фигурная скобка, которая являются концом объявлений этих переменных), имеют указанную область действия, если не использована другая директива. В приведенном примере директива @protected гарантирует, что следующие после нее переменные экземпляра будут доступны для методов подклассов и класса Printer.
Директива @public делает переменные экземпляра доступными для других методов или функций с помощью оператора-указателя (->), который описывается в главе 13. Такой доступ к переменным экземпляра не допускается практикой надежного программирования, поскольку он нарушает концепцию инкапсуляции данных (то есть скрытие классом своих переменных экземпляра). Внешние переменные
Если написать int gMoveNumber = 0;
в начале программы — вне любого метода, определения класса или функции, — то ее значение можно использовать из любого места данного модуля. В этом случае gMoveNumber определяется как гло б а ль н а я переменная. Обычно принято использовать букву g как первую букву глобальной переменной, чтобы обозначить для читателя программы ее область действия.
На самом деле такое определение переменной gMoveNumber делает ее значение доступным из других файлов. Приведенный оператор определяет переменную gMoveNumber не только как глобальную переменную, но и как внешнюю глобальную переменную.
Внешней (external) переменной является переменная, чье значение может изменяться другими методами или функциями. Внутри модуля, из которого требуется доступ к этой переменной, она объявляется обычным образом, перед ее объявлением ставится ключевое слово extern. Это указывает системе, что требуется доступ к глобально определенной переменной из другого файла. Ниже показан пример объявления переменной gMoveNumber как внешней переменной. extern int gMoveNumber;
Модуль, в котором появилось это объявление, может выполнять доступ к переменной gMoveNumber и изменять ее значение. Другие модули тоже могут выполнять доступ к значению gMoveNumber, используя в своем файле аналогичное объявление extern.
При работе с внешними переменными соблюдайте следующее важное правило. Такая переменная должна быть определена среди ваших исходных файлов. Она должна быть объявлена вне любого метода или функции, и перед ней не должно быть ключевого слова extern, например, Дополнительно такой переменной может быть присвоено начальное значение, как показано выше.
Второй способ определения внешней переменной — это объявление переменной вне любой функции с ключевым словом extern перед этим объявлением и явным присваиванием начального значения этой переменной, например, extern int gMoveNumber = 0;
Однако при таком способе компилятор предупредит вас, что вы объявили переменную как extern и одновременно
присвоили ей значение. Использование слова extern делает его объявлением, а не определением для переменной, а объявление не вызывает выделения памяти для переменной — это происходит в результате определения. В приведенном примере это правило нарушается, поскольку объявление интерпретируется как определение (поскольку переменной присваивается начальное значение).При работе с внешними переменными можно объявлять переменную как extern во многих местах, но определить ее можно только один раз. Рассмотрим программу как пример использования внешних переменных. Мы определили класс с именем Foo и ввели следующий код в файл main.m: #import "Foo.h" int gGlobalVar = 5; int main (int argc, char *argc[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Foo *myFoo = [[Foo alloc] init]; NSLog (@"%i", gGlobalVar); [myFoo setgGlobalVar: 100] NSLog (@"%i", gGlobalVar); [myFoo release]; [pool drain]; return 0; }
Определение глобальной переменной gGlobalVar в этой программе делает ее значение доступным для любого метода (или функции), где используется соответствующее объявление extern. Предположим, что используется метод класса Foo с именем setgGlobalVar:. -(void) setgGlobalVar: (int) val { extern int gGlobalVar; gGlobalVar = val; }
Программа выведет следующие результаты. 5 100
Таким образом, метод setgGlobalVar: может выполнять доступ к внешней переменной gGlobalVar и изменять ее значение.
В тех случаях, когда доступ к значению gGlobalVar требуется многим методам, проще включить объявление extern только один раз в начале файла. Но если доступ к этой переменной требуется одному методу или небольшому числу методов, то имеет смысл включать объявления extern в каждый из таких методов; это сделает программу более организованной и ограничит использование конкретной переменной теми функциями, в которых она действительно требуется. Отметим, что если переменная определена внутри файла, содержащего код, который выполняет доступ к этой переменной, то отдельные объявления extern не требуются. Статические переменные
Только что показанный пример нарушает принцип инкапсуляции данных и практику надежного объектно-ориентированного программирования. Но вам может потребоваться работа с переменными, значения которых должны быть доступны для вызова из различных методов. Может показаться, что нет смысла делать переменную gGlobalVar переменной экземпляра в классе Foo, надежнее «скрыть» ее в классе Foo путем ограничения доступа к ней методами-установщиками (setter) и методами-получателями (getter), определенными для этого класса.
Теперь вы знаете, что любая переменная, определенная вне метода, является не только глобальной, но и внешней переменной. Но существует много ситуаций, когда нужно определить переменную, которая является глобальной, но не является внешней. Иначе говоря, вам нужно определить глобальную переменную, которая будет локальной для определенного модуля (файла). Имеет смысл определять такую переменную, если доступ к ней требуется только тем методам, которые содержатся в конкретном определении класса. Это можно сделать, определив переменную как статическую (static) внутри файла, содержащего секцию implementation для конкретного класса.