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

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

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

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

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

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

Ответ 1

Первый вопрос - какой объем вы хотите, чтобы ваши константы имели, что действительно два вопроса:

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

Если они являются специфическими и внутренними для одного класса, объявите их как 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, мне нужно импортировать файл, или константы будут доступны глобально без импорта файла?

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

Ответ 2

FOUNDATION_EXPORT

Рассмотрите возможность использования FOUNDATION_EXPORT для большей совместимости, чем extern, поскольку он определен в базе и компилируется в совместимые форматы для 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