Здесь вас задают два вопроса: один о константах и один о внешнем. Эти два не обязательно связаны между собой.
Во-первых, const: константы не намного больше, чем, как вы сказали, они не могут быть изменены программно. Различные вещи могут быть постоянными, хотя, в зависимости от того, как вы их объявляете. Например, в вашем примере:
NSString * const MyConstant = @"foo";
Вы указали постоянный указатель на непостоянный объект NSString; ключевое слово const
находится справа от звезды, поэтому оно относится к указателю. Таким образом, это:
MyConstant = @"bar";
приведет к ошибке компиляции, поскольку он пытается передать MyConstant
, чтобы указать на другой NSString.
Если ключевое слово const
расположено слева от звезды, оно будет ссылаться на объект, на который ссылается указатель (в данном случае лежащая в основе структура NSString). Это, вероятно, не то, что вы хотите большую часть времени в Objective C. Обратите внимание, что положение const
ключевого слова относительно идентификатора типа не имеет значения, так это:
const NSString *MyConstant = @"foo";
и это:
NSString const *MyConstant = @"foo";
означает то же самое.Вы можете также юридически объявить как указатель и эталонное значение сопзЬ, для максимального константность:
const NSString * const MyConstant = @"foo";
Во-вторых, ехЬегп: extern
просто позволяет объявить переменную в одном модуле компиляции, и пусть компилятор знать, что вы определили эту переменную в отдельном модуле компиляции. Обычно вы используете это только для глобальных значений и констант.
Вы можете представить себе блок компиляции как один файл .m
, а также все файлы .h
, которые он содержит. Во время сборки компилятор компилирует каждый файл .m в отдельный файл .o
, а затем компоновщик соединяет их все вместе в один двоичный файл. Обычно то, как один блок компиляции знает об идентификаторах (таких как имя класса), объявленных в другом модуле компиляции, является импортированием файла заголовка. Но в случае глобалов они часто не являются частью открытого интерфейса класса, поэтому они часто объявляются и определяются в файле .m
.
Если модуль компиляции объявляет глобальный в .m
файле:
#import "A.h"
NSString *someGlobalValue;
и модуль компиляции B хочет использовать, что глобальное:
#import "B.h"
extern NSString *someGlobalValue;
@implementation B
- (void)someFunc {
NSString *localValue = [self getSomeValue];
if (localValue isEqualToString:someGlobalValue]) {
...
}
}
блок B должен каким-то образом указать компилятору использовать переменная, объявленная блоком A. Он не может импортировать файл .m
, где происходит объявление, поэтому он использует extern
, чтобы сообщить компилятору, что переменная существует в другом месте.
Обратите внимание, что если блок А и блок B как есть эта линия на верхнем уровне файла:
NSString *someGlobalValue;
то у вас есть две единицы компиляции декларирующих ту же глобальную переменную, и компоновщик не сможет с дублирующейся символьной ошибкой. Если вы хотите иметь переменную, как это, что существует только внутри модуля компиляции, и является невидимым для других единиц компиляции (даже если они используют extern
), вы можете использовать static
ключевое слово:
static NSString * const someFileLevelConstant = @"wibble";
Это может быть полезна для констант, которые вы хотите использовать в одном файле реализации, но не потребуется в другом месте.
Приветствия тем, кто сломает его. Сломай. – 2012-09-30 19:47:00