it-swarm.com.ru

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

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

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

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

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

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

154
Robert Audi

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

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

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

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

380
Peter Hosey

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
8
Steve Moser