Константы в Objective-C

Я занимаюсь разработкой приложения Cocoa и использую константы NSString в качестве способа хранения имен ключей для своих предпочтений.

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

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

вопрос задан 11.02.2009
Allyn
10087 репутация

13 ответов


  • 1248 рейтинг

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

    // Constants.h
    FOUNDATION_EXPORT NSString *const MyFirstConstant;
    FOUNDATION_EXPORT NSString *const MySecondConstant;
    //etc.
    

    (вы можете использовать extern вместо FOUNDATION_EXPORT, если ваш код не будет использоваться в смешанных средах C / C ++ или на других платформах)

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

    Вы определяете эти константы в. м файл как

    // Constants.m
    NSString *const MyFirstConstant = @"FirstConstant";
    NSString *const MySecondConstant = @"SecondConstant";
    

    Константы. m должен быть добавлен к цели вашего приложения / фреймворка, чтобы он был связан с конечным продуктом.

    Преимущество использования строковых констант вместо d-констант #define состоит в том, что вы можете проверить равенство с помощью сравнения указателей (stringInstance == MyFirstConstant), которое намного быстрее, чем сравнение строк ([stringInstance isEqualToString:MyFirstConstant]) (и легче для чтения, IMO).

    ответ дан Barry Wark, с репутацией 99877, 11.02.2009
  • 264 рейтинг

    Самый простой способ:

    // Prefs.h
    #define PREFS_MY_CONSTANT @"prefs_my_constant"
    

    Лучший путь:

    // Prefs.h
    extern NSString * const PREFS_MY_CONSTANT;
    
    // Prefs.m
    NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";
    

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

    ответ дан Andrew Grant, с репутацией 49768, 11.02.2009
  • 182 рейтинг

    Есть также одна вещь, чтобы упомянуть. Если вам нужна не глобальная константа, вы должны использовать ключевое слово static.

    Пример

    // In your *.m file
    static NSString * const kNSStringConst = @"const value";
    

    Из-за ключевого слова static этот констант не виден вне файла.


    Незначительная коррекция @QuinnTaylor : статические переменные видны в модуле компиляции . Обычно это сингл. m (как в этом примере), но он может укусить вас, если вы объявите его в заголовке, который включен в другом месте, так как вы получите ошибки компоновщика после компиляции

    ответ дан kompozer, с репутацией 1994, 12.02.2009
  • 117 рейтинг

    В принятом (и правильном) ответе говорится, что «вы можете включить это [Константы. h] файл. , , в предварительно скомпилированном заголовке для проекта. "

    Как новичок, мне было трудно сделать это без дальнейшего объяснения - вот как: в вашем префиксе YourAppNameHere. Файл pch (это имя по умолчанию для предварительно скомпилированного заголовка в XCode), импортируйте ваши константы. h внутри блока #ifdef __OBJC__ .

    #ifdef __OBJC__
      #import 
      #import 
      #import "Constants.h"
    #endif
    

    Также обратите внимание, что константы. ч и константы. В m файлах не должно быть абсолютно ничего, кроме того, что описано в принятом ответе. (Нет интерфейса или реализации).

    ответ дан Victor Van Hee, с репутацией 6144, 18.09.2011
  • 50 рейтинг

    Я обычно использую способ Барри Уорка и Рахула Гупты.

    Хотя я не люблю повторять одни и те же слова в обоих. рука . м файл. Обратите внимание, что в следующем примере строка почти идентична в обоих файлах:

    // file.h
    extern NSString* const MyConst;
    
    //file.m
    NSString* const MyConst = @"Lorem ipsum";
    

    Поэтому, что мне нравится делать - это использовать некоторые препроцессорные механизмы на языке C. Позвольте мне объяснить на примере.

    У меня есть файл заголовка, который определяет макрос STR_CONST(name, value):

    // StringConsts.h
    #ifdef SYNTHESIZE_CONSTS
    # define STR_CONST(name, value) NSString* const name = @ value
    #else
    # define STR_CONST(name, value) extern NSString* const name
    #endif
    

    по моему. час/. м пара, где я хочу определить константу, я делаю следующее:

    // myfile.h
    #import 
    
    STR_CONST(MyConst, "Lorem Ipsum");
    STR_CONST(MyOtherConst, "Hello world");
    
    // myfile.m
    #define SYNTHESIZE_CONSTS
    #import "myfile.h"
    

    et вуаля, у меня есть вся информация о константах в. только файл h

    ответ дан Krizz, с репутацией 9899, 2.12.2011
  • 25 рейтинг

    Небольшая модификация предложения @Krizz, так что он работает правильно, если файл заголовка констант должен быть включен в PCH, что довольно нормально. Поскольку оригинал импортируется в PCH, он не будет перезагружать его в файл .m, и, таким образом, вы не получите никаких символов, а компоновщик недоволен.

    Однако следующая модификация позволяет ему работать. Это немного запутанно, но это работает.

    Вам понадобится , 3 файла , файл .h с определениями констант, файл .h и файл .m, я буду использовать ConstantList.h, Constants.h и Constants.m соответственно. содержимое Constants.h просто:

    // Constants.h
    #define STR_CONST(name, value) extern NSString* const name
    #include "ConstantList.h"
    

    и файл Constants.m выглядит следующим образом:

    // Constants.m
    #ifdef STR_CONST
        #undef STR_CONST
    #endif
    #define STR_CONST(name, value) NSString* const name = @ value
    #include "ConstantList.h"
    

    Наконец, файл ConstantList.h содержит фактические объявления в нем, и это все:

    // ConstantList.h
    STR_CONST(kMyConstant, "Value");
    …
    

    Несколько вещей, чтобы отметить:

    1. Мне пришлось переопределить макрос в файле .m после #undef, чтобы использовать его для макроса.

    2. Мне также пришлось использовать #include вместо #import, чтобы это работало должным образом и не позволяло компилятору видеть предварительно скомпилированные значения.

    3. Это потребует перекомпиляции вашего PCH (и, вероятно, всего проекта) всякий раз, когда какие-либо значения изменяются, что не имеет место, если они разделены (и дублированы) как обычно.

    Надеюсь, что это полезно для кого-то.

    ответ дан Scott Little, с репутацией 1632, 3.12.2011
  • 25 рейтинг

    У меня сам есть заголовок, предназначенный для объявления констант NSStrings, используемых для предпочтений, например:

    extern NSString * const PPRememberMusicList;
    extern NSString * const PPLoadMusicAtListLoad;
    extern NSString * const PPAfterPlayingMusic;
    extern NSString * const PPGotoStartupAfterPlaying;
    

    Затем объявив их в сопроводительном письме. м файл:

    NSString * const PPRememberMusicList = @"Remember Music List";
    NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
    NSString * const PPAfterPlayingMusic = @"After playing music";
    NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";
    

    Этот подход хорошо мне послужил.

    Редактировать: Обратите внимание, что это работает лучше всего, если строки используются в нескольких файлах. Если только один файл использует его, вы можете просто сделать #define kNSStringConstant @"Constant NSString" в. m файл, который использует строку.

    ответ дан MaddTheSane, с репутацией 2179, 26.01.2013
  • 14 рейтинг
    // Prefs.h
    extern NSString * const RAHUL;
    
    // Prefs.m
    NSString * const RAHUL = @"rahul";
    
    ответ дан rahul gupta, с репутацией 396, 28.09.2011
  • 12 рейтинг

    Как сказал Abizer, вы можете поместить его в файл PCH. Другой способ, который не так грязен, - сделать включаемый файл для всех ваших ключей, а затем либо включить его в файл, в котором вы используете ключи, либо включить его в PCH. С ними в их собственном файле включения, который, по крайней мере, дает вам одно место для поиска и определения всех этих констант.

    ответ дан Grant Limberg, с репутацией 13405, 11.02.2009
  • 11 рейтинг

    Если вы хотите что-то вроде глобальных констант; Быстрый грязный способ - поместить объявления констант в файл pch.

    ответ дан Abizern, с репутацией 97378, 11.02.2009
  • 7 рейтинг

    Попробуйте использовать метод класса:

    +(NSString*)theMainTitle
    {
        return @"Hello World";
    }
    

    Я использую это иногда.

    ответ дан groumpf, с репутацией 171, 6.12.2009
  • 7 рейтинг

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

    #import 
    
    @interface iCode_Framework : NSObject
    
    @property (readonly, nonatomic) unsigned int iBufCapacity;
    @property (readonly, nonatomic) unsigned int iPort;
    @property (readonly, nonatomic) NSString * urlStr;
    
    @end
    
    #import "iCode_Framework.h"
    
    static iCode_Framework * instance;
    
    @implementation iCode_Framework
    
    @dynamic iBufCapacity;
    @dynamic iPort;
    @dynamic urlStr;
    
    - (unsigned int)iBufCapacity
    {
        return 1024u;
    };
    
    - (unsigned int)iPort
    {
        return 1978u;
    };
    
    - (NSString *)urlStr
    {
        return @"localhost";
    };
    
    + (void)initialize
    {
        if (!instance) {
            instance = [[super allocWithZone:NULL] init];
        }
    }
    
    + (id)allocWithZone:(NSZone * const)notUsed
    {
        return instance;
    }
    
    @end
    

    И он используется следующим образом (обратите внимание на использование сокращения для констант c - каждый раз сохраняется [[Constants alloc] init]):

    #import "iCode_FrameworkTests.h"
    #import "iCode_Framework.h"
    
    static iCode_Framework * c; // Shorthand
    
    @implementation iCode_FrameworkTests
    
    + (void)initialize
    {
        c  = [[iCode_Framework alloc] init]; // Used like normal class; easy to mock!
    }
    
    - (void)testSingleton
    {
        STAssertNotNil(c, nil);
        STAssertEqualObjects(c, [iCode_Framework alloc], nil);
        STAssertEquals(c.iBufCapacity, 1024u, nil);
    }
    
    @end
    
    ответ дан Howard Lovatt, с репутацией 729, 16.07.2012
  • 7 рейтинг

    Если вам нравится константа пространства имен, вы можете использовать struct, Friday, Q & amp; A 2011-08-19: Константы и функции в пространстве имен

    // in the header
    extern const struct MANotifyingArrayNotificationsStruct
    {
        NSString *didAddObject;
        NSString *didChangeObject;
        NSString *didRemoveObject;
    } MANotifyingArrayNotifications;
    
    // in the implementation
    const struct MANotifyingArrayNotificationsStruct MANotifyingArrayNotifications = {
        .didAddObject = @"didAddObject",
        .didChangeObject = @"didChangeObject",
        .didRemoveObject = @"didRemoveObject"
    };
    
    ответ дан onmyway133, с репутацией 22956, 25.07.2015