Глобальные переменные и static
Объявление переменной вне какого-либо метода (и в Objective-C внутри или снаружи @implementation
/ @end
делает время жизни переменной глобальным, то есть переменная будет существовать во время весь период выполнения заявки.
Глобальная переменная без квалификации или только с квалификаторами const
и / или volatile
, видима из любого места. Так, например:
NSString *MyApplicationName;
объявляет глобальную переменную MyApplicationName
, к которой можно получить доступ из любого места приложения.
Видимость глобальной переменной (но не ее времени жизни) может быть ограничена только файлом (точнее, «единицей компиляции», допускающим один файл, включая другие), содержащим объявление, квалифицируя его как static
. Так, например:
static NSString *MyClassName;
объявляет глобальную переменную MyClassName
, которая видна только из текущего модуля компиляции.
Использование static
квалифицированных глобальных объявлений в @implementation
/ @end
является наиболее близкой вещью, которую Objective-C предлагает к "переменным класса" других языков.
Вы не должны размещать объявления глобальных переменных, квалифицированных static
или нет, в заголовочных файлах, так как это приведет к нескольким различным объявлениям - возникнет ошибка, если нет квалификатора static
, и несколько различных переменных с разными областями видимости, если таковая имеется.
Классификатор extern
Спецификатор extern
делает что-то совсем другое.
Первоначальный смысл (теперь допускается небольшое ослабление, см. Ниже) - просто определить тип и имя глобальной переменной, которая объявлена в другом месте. То есть вы говорите компилятору «есть глобальная переменная некоторого типа и имени, которую я хотел бы использовать, которая будет предоставлена другим модулем компиляции». Например:
extern NSString *MyApplicationName;
заявляет, что некоторая единица компиляции содержит объявление (которое не должно быть static
квалифицированным):
NSString *MyApplicationName;
Квалифицированное объявление extern
само по себе не вызывает выделение какого-либо хранилища для глобальной переменной.
Вы делаете размещаете extern
квалифицированные объявления в заголовочных файлах, вот как модуль компиляции объявляет глобальные переменные, которые он хочет экспортировать. Вы также можете поместить их в файлы кода для ссылки на глобальные переменные, объявленные в другом месте. В файле кода вы можете поместить квалифицированное объявление extern
вне любого метода / функции - в этом случае имя / тип доступно для всей единицы компиляции - или внутри метода / функции - в этом случае видимость имя / тип ограничено только этим методом / функцией.
Небольшое расслабление
Изначально вам нужно было одно не extern
объявление квалификатора, чтобы удовлетворить любые extern
квалифицированные. Однако это было позже изменено, если при связывании различных модулей компиляции ни один из них не объявляет глобальную переменную, на которую ссылается какое-то квалифицированное объявление extern
, то компоновщик (обычно?) Просто генерирует саму переменную и добавляет ее в результирующий двоичный файл, а не выдает «отсутствующую глобальную» ошибку. Лучшая практика программирования - не полагаться на это ослабление - всегда иметь квалифицированное объявление, не являющееся extern
для каждой глобальной переменной.