Некоторые определения
A литерал - это значение, которое является неизменным по определению. например: 10
константа - переменная или указатель только для чтения. например: const int age = 10;
строковый литерал является выражением типа @""
. Компилятор заменит это экземпляром NSString
.
строковая константа является указателем только для чтения на NSString
. например: NSString *const name = @"John";
Некоторые комментарии в последней строке:
- Это постоянный указатель, а не постоянный объект 1 .
objc_sendMsg
2 не волнует, если вы квалифицируете объект как const
. Если вы хотите неизменный объект, вы должны закодировать эту неизменность внутри объекта 3 .
- Все
@""
выражения действительно неизменны. Они заменяются 4 во время компиляции на экземпляры NSConstantString
, которые являются специализированным подклассом NSString
с фиксированной схемой памяти 5 . Это также объясняет, почему NSString
является единственным объектом, который может быть инициализирован во время компиляции 6 .
A константа будет const NSString* name = @"John";
, что эквивалентно NSString const* name= @"John";
. Здесь и синтаксис, и намерение программиста ошибочны: const <object>
игнорируется, а экземпляр NSString
(NSConstantString
) уже неизменен.
1 Ключевое слово const
применяется ко всему, что находится непосредственно слева от него. Если слева от него ничего нет, это относится ко всему, что находится справа от него.
2 Это функция, которую среда выполнения использует для отправки всех сообщений в Objective-C, и, следовательно, то, что вы можете использовать для изменения состояния объекта.
3 Пример: в const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects];
const не мешает последнему утверждению.
4 Код LLVM, который переписывает выражение: RewriteModernObjC::RewriteObjCStringLiteral
в RewriteModernObjC.cpp.
5 Чтобы увидеть определение NSConstantString
, cmd + щелкните его в Xcode.
6 Создание констант времени компиляции для других классов будет простым, но для этого потребуется, чтобы компилятор использовал специализированный подкласс. Это нарушит совместимость со старыми версиями Objective-C.
Вернуться к вашей цитате
Каркасы Какао ожидают, что глобальные строковые константы, а не
строковые литералы используются для ключей словаря, уведомления и
имена исключений и некоторые параметры методов, которые принимают строки. Вы
всегда следует предпочитать строковые константы перед строковыми литералами
есть выбор. Используя строковые константы, вы получаете помощь
компилятор для проверки орфографии и, следовательно, для избежания ошибок во время выполнения.
Там написано, что литералы подвержены ошибкам. Но это не говорит о том, что они также медленнее. Сравните:
// string literal
[dic objectForKey:@"a"];
// string constant
NSString *const a = @"a";
[dic objectForKey:a];
Во втором случае я использую ключи с указателями const, поэтому вместо [a isEqualToString:b]
я могу сделать (a==b)
. Реализация isEqualToString:
сравнивает хеш, а затем запускает функцию C strcmp
, так что это медленнее, чем прямое сравнение указателей. Именно поэтому почему константы лучше: они быстрее сравниваются и менее подвержены ошибкам.
Если вы также хотите, чтобы ваша константа была глобальной, сделайте это так:
// header
extern NSString *const name;
// implementation
NSString *const name = @"john";