Подтвердить что ты не робот

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

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

Спасибо

UPDATE: В этом случае полезно использовать #define или есть лучший подход?

/* Constants Definition */
#define SERVER_URL @"http://subdomain.domain.edu.ar/Folder/"
NSString *const ServerURL = SERVER_URL;
NSString *const LoginURL = [email protected]"welcome.asp";
NSString *const CommandURL = [email protected]"com.asp";
4b9b3361

Ответ 1

Практическая причина использования константы в отличие от определения заключается в том, что вы можете делать прямые сравнения (используя ==) вместо использования 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])
{
    ...
}

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

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

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

Ответ 2

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

Ответ 3

Самый лучший аргумент, который я слышал, состоит в том, что строки const отображаются в отладчике, тогда как макросы - нет.

Ответ 4

static NSString * const SERVER_URL = @"http://subdomain.domain.edu.ar/Folder/";

Ответ 5

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

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

extern NSString *MyConstantString;

Основной файл:

NSString *MyConstantString = @"String value";