Каков наилучший способ создания констант в Objective-C

156

Я создаю клиент Reddit для учебных целей. Мне нужно иметь файл с константами в нем. Я думал об импорте файла в Reddit-Prefix.pchфайл, чтобы сделать константы доступными для всех файлов. Это хороший способ делать вещи? Кроме того, я провел исследование и нашел несколько методов для создания констант, но я не знаю, какой из них использовать:

  • #define макрос
  • const
  • static const
  • extern const
  • enum

Так какой путь является предпочтительным? Что такое конвенция? Я знаю, что «это зависит», но мой вопрос более конкретно: каковы варианты использования для каждого из этих решений?

Также, если вы используете extern const, нужно ли импортировать файл, или константы будут доступны глобально без импорта файла?

Я мог бы логично сделать вывод, что enumэто лучший выбор при определении чего-то вроде пользовательских доменов ошибок (на самом деле я прав?). А что насчет остальных?

Роберт Ауди
источник
stackoverflow.com/questions/11153156/… пожалуйста, перейдите по этой ссылке ... Ваше решение в этом посте
Пользователь 1531343
3
@BhavikKama: это более узкий вопрос, в отличие от двух конкретных решений.
Питер Хоси
for - static const, #define, enum, эта ссылка полезна stackoverflow.com/questions/1674032/static-const-vs-define-in-c, которая обеспечивает хорошее объяснение этих трех альтернатив const
Пользователь 1531343
enumполезно только для интегральных значений. #defineи константы могут быть любого типа данных.
rmaddy
const, static constИ extern constвсе же за исключением объема. Так что на самом деле есть только три варианта.
rmaddy

Ответы:

385

Первый вопрос заключается в том, какую область видимости вы хотите иметь для своих констант, а на самом деле это два вопроса:

  • Являются ли эти константы специфичными для одного класса, или имеет смысл иметь их во всем приложении?
  • Если они специфичны для класса, предназначены ли они для использования клиентами класса или только внутри класса?

Если они являются специфическими и внутренними для одного класса, объявите их static constв начале файла .m следующим образом:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Если они относятся к одному классу, но должны быть публичными / использоваться другими классами, объявите их как externв заголовке и определите их в .m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Если они должны быть глобальными, объявите их в заголовке и определите их в соответствующем модуле, специально для этих констант.

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

Почему нет #define?

Старый ответ - «у макросов нет информации о типе», но сегодня компиляторы достаточно умны в отношении выполнения всей проверки типов для литералов (то, к чему расширяются макросы), а также для переменных.

Современный ответ таков: отладчик не будет знать о ваших макросах. Вы не можете сказать [myThing addObserver:self forKey:MyThingNotificationKey]в команде отладчика, MyThingNotificationKeyявляется ли макрос; отладчик может знать об этом, только если это переменная.

Почему нет enum?

Что ж, rmaddy опередил меня в комментариях: enumможет определять только целочисленные константы. Такие вещи, как номера серийных идентификаторов, битовые маски, четырехбайтовые коды и т. Д.

Для этих целей enumотлично подходит, и вы обязательно должны его использовать. (Еще лучше, если использовать те NS_ENUMи NS_OPTIONSмакросы .) Для других вещей, вы должны использовать что - то другое; enumне делает ничего, кроме целых чисел.

И другие вопросы

Я думал об импорте файла в файл Reddit-Prefix.pch, чтобы сделать константы доступными для всех файлов. Это хороший способ делать вещи?

Вероятно, безвреден, но, вероятно, чрезмерен. Импортируйте ваши константы заголовков, где они вам нужны.

Каковы варианты использования для каждого из этих решений?

  • #defineДовольно ограничен. Я, честно говоря, не уверен, что есть веская причина использовать это для констант больше.
  • const: Лучше всего подходит для локальных констант. Кроме того, вы должны использовать это для того, который вы объявили в заголовке и теперь определяете.
  • static const: Лучше всего подходит для констант, специфичных для файлов (или классов).
  • extern const: Вы должны использовать это при экспорте константы в заголовке.

Также, если вы используете extern const, нужно ли импортировать файл, или константы будут доступны глобально без импорта файла?

Вам необходимо импортировать файл, либо в каждый файл, в котором вы его используете, либо в заголовок префикса.

Питер Хоси
источник
3
Почему бы не использовать static NSString *constв .hфайле вообще?
Юлиан Онофрей
3
@IulianOnofrei: Вы можете, если это в приложении, а не в фреймворке. Если вы это сделаете static NSString *const foo = @"foo";, то ваш заголовок определяет, что это за строка, и она должна быть везде одинаковой - если вы когда-нибудь измените строку, и разные стороны будут использовать разные версии заголовка с другой строкой, то строки при запуске не будут совпадать время. В платформе вы хотите предоставить доступ только к символу и позволить платформе быть единственным источником истинного значения этого символа, чтобы все получали одну и ту же строку из одного места. Вот что externтебя заводит.
Питер Хоси
Дополнительное примечание к #defines: у них не гарантируется одинаковый адрес в памяти (в зависимости от того, как они объявлены, они могут выделять новый экземпляр при каждом использовании), поэтому использование myObject == MyDefineне всегда будет работать должным образом, но myObject == MyStaticConstбудет.
Бен Легжеро
Имеет ли смысл правописание, static NSString *constа не static NSString const*?? Какие-нибудь различия?
kokos8998
@ kokos8998 это имеет значение? Да, это так. static NSString const *это то же самое, что static const NSString *и означает «(изменяемый) указатель на константу NSString», что здесь немного бесполезно, поскольку NSString уже неизменна. То, что вы хотите только static NSString * const- что является «постоянным указателем на
Дэвид
8

FOUNDATION_EXPORT

Рассмотрите возможность использования FOUNDATION_EXPORTдля большей совместимости, чем externэто, поскольку она определена в фундаменте и компилируется в совместимые форматы для C, C ++ и Win32.

Как определено в NSObjCRuntime.h

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
Стив Мозер
источник