Objective C #define директива демонизируется для Строковых констант

У меня есть чтение в нескольких сообщениях и в инструкциях по коду Apple, которые в Строковых константах Objective C должны быть определены как экстерн NSString *const MY_CONSTANT; и что #define директивы нужно избежать. Почему это? Я знаю это #define выполняется во время перед компиляцией, но вся строка совместно использует тот же адрес памяти. Единственное преимущество, которое я считал, состояло в том, что, если константа должна быть обновлена или изменилась, Вы не должны перекомпилировать свой весь проект. Так, чтобы я s причина, почему #define нужно избежать?

Спасибо

ОБНОВЛЕНИЕ: В этом случае хорошо для использования #define или существует лучший подход?

/* Constants Definition */
#define SERVER_URL @"http://subdomain.domain.edu.ar/Folder/"
NSString *const ServerURL = SERVER_URL;
NSString *const LoginURL = SERVER_URL@"welcome.asp";
NSString *const CommandURL = SERVER_URL@"com.asp";
12
задан GuidoMB 29 December 2009 в 23:38
поделиться

4 ответа

Практическая причина использования константы в отличие от определения заключается в том, что вы можете делать прямые сравнения (используя ==) вместо использования isEqual:. Рассмотрим:

NSString * const kSomeStringConstant = @"LongStringConstantIsLong";
...
[someArray addObject:kSomeStringConstant];
if ([someArray lastObject] == kSomeStringConstant)
{
   ...
}

Это сработает, так как сравнение == будет сравнивать идентичные константные указатели с одним объектом NSString. Однако, используя #define:

#define STRING_CONSTANT @"MacrosCanBeEvil";
...
[SomeArray addObject:STRING_CONSTANT]; // a new const `NSString` is created
if ([someArray lastObject] == STRING_CONSTANT) // and another one, here.
{
    ...
}

Это не сработало бы -, так как эти две строки будут иметь уникальные указатели. Для того, чтобы эффективно сравнить их, вам пришлось бы делать посимвольное сравнение, используя isEqual:

if ([[someArray lastObject] isEqual:STRING_CONSTANT])
{
    ...
}

Это может быть гораздо более дорогостоящим с точки зрения времени исполнения, чем простое == сравнение.

Другой мотив может быть размер самого исполняемого файла. На самом деле #определенная константа появлялась бы на месте, где бы она ни использовалась в коде. Это может означать, что строка появляется много раз в вашем исполняемом файле. Напротив, константа должна (в современных компиляторах) быть определена только один раз, и все дальнейшие использования ссылались бы на указатель на это одно определение.

Теперь, прежде чем кто-то наорет на меня за преждевременную оптимизацию, считайте, что эти два подхода практически идентичны с точки зрения реализации, но метод константы намного превосходит по размеру кода и времени исполнения.

.
17
ответ дан 2 December 2019 в 04:25
поделиться

Не гарантируется, что в целом приложении будет только один объект NXConstantString для заданного строкового литерала. Вполне вероятно, что разные модули компиляции могут иметь разные объекты для одной и той же константной строки. Например, если кто-то напишет плагин, то одна константная строка будет сгенерирована для вхождений этого NSString литерала в плагине, а другая - для вхождений в хост-приложение, и это не будет указатель-эквивалент.

.
10
ответ дан 2 December 2019 в 04:25
поделиться

Лучший аргумент, который я слышал, это то, что строки const появляются в отладчике, а макросы нет.

.
9
ответ дан 2 December 2019 в 04:25
поделиться

Насколько я знаю, #define позволяет определить только строковые константы в стиле C. Чтобы создать объект константы NSString, необходимо объявить его в заголовке, а затем дать ему значение в одном из .m файлов.

Заголовочный файл:

extern NSString *MyConstantString;

Main file:

NSString *MyConstantString = @"String value";

-2
ответ дан 2 December 2019 в 04:25
поделиться