Який найкращий спосіб створити константи в Objective-C


156

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

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

То який спосіб є кращим? Що таке конвенція? Я знаю, що "це залежить", але моє питання конкретніше таке: які випадки використання для кожного з цих рішень?

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

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


stackoverflow.com/questions/11153156/…, будь ласка, перейдіть за цим посиланням ... ваше рішення знаходиться у цій публікації
Користувач 1531343

3
@BhavikKama: Це більш вузьке питання, яке протиставляє два конкретні рішення.
Пітер Хосей

для - static const, #define, enum, це посилання є корисним stackoverflow.com/questions/1674032/static-const-vs-define-in-c, що дає хороші пояснення щодо цих 3 альтернатив 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- а це "постійний вказівник на NSString"
Девід

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.