首页 文章

Objective-C中的常量

提问于
浏览
980

我正在开发一个Cocoa应用程序,并且我使用常量 NSString 来作为存储我的首选项的键名的方法 .

我知道这是一个好主意,因为它可以在必要时轻松更改密钥 . 此外,它是整个'将您的数据与逻辑分离'的概念 .

无论如何,是否有一种很好的方法可以为整个应用程序定义一次这些常量?我确信这是一种简单而聪明的方式,但是现在我的课程只是重新定义了他们使用的课程 .

13 回答

  • 184

    您应该创建一个头文件,如

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

    (如果您的代码不会在混合C / C环境或其他平台上使用,则可以使用 extern 而不是 FOUNDATION_EXPORT

    您可以在使用常量的每个文件中或在项目的预编译头中包含此文件 .

    您可以在.m文件中定义这些常量

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

    应将Constants.m添加到应用程序/框架的目标中,以便将其链接到最终产品 .

    使用字符串常量而不是 #define 'd常量的优点是可以使用指针比较( stringInstance == MyFirstConstant )测试相等性,这比字符串比较( [stringInstance isEqualToString:MyFirstConstant] )快得多(并且更容易阅读,IMO) .

  • 268

    最简单的方法:

    // 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";
    

    第二个好处的一个好处是更改常量的值不会导致整个程序的重建 .

  • 25

    还有一件事要提 . 如果需要非全局常量,则应使用 static 关键字 .

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

    由于 static 关键字,此const在文件外部不可见 .


    Minor correction by @QuinnTaylor: 静态变量在编译单元中可见 . 通常,这是一个单独的.m文件(如本例所示),但如果你在其他地方包含的头文件中声明它,它会咬你,因为你在编译后会遇到链接器错误

  • 7

    接受的(和正确的)答案说“你可以在项目的预编译头中包含这个[Constants.h]文件 . ”

    作为一个新手,我很难做到这一点而没有进一步的解释 - 这里是如何:在你的YourAppNameHere-Prefix.pch文件中(这是Xcode中预编译头的默认名称),在 #ifdef __OBJC__ 块中导入你的Constants.h .

    #ifdef __OBJC__
      #import <UIKit/UIKit.h>
      #import <Foundation/Foundation.h>
      #import "Constants.h"
    #endif
    

    另请注意,除了接受的答案中描述的内容之外,Constants.h和Constants.m文件中除了其他内容之外绝对不应包含任何其他内容 . (没有接口或实现) .

  • 25

    我通常使用Barry Wark和Rahul Gupta发布的方式 .

    虽然,我不喜欢在.h和.m文件中重复相同的单词 . 请注意,在以下示例中,两个文件中的行几乎相同:

    // 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
    

    在我想要定义常量的.h / .m对中,我执行以下操作:

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

    et voila,我只有.h文件中有关常量的所有信息 .

  • 1259

    稍微修改一下@Krizz的建议,这样如果将常量头文件包含在PCH中它就能正常工作,这是很正常的 . 由于原始文件被导入到PCH中,因此它不会将其重新加载到 .m 文件中,因此您没有符号,链接器也不满意 .

    但是,以下修改允许它工作 . 这有点令人费解,但它确实有效 .

    你需要 3 文件, .h 文件有常量定义, .h 文件和 .m 文件,我将分别使用 ConstantList.hConstants.hConstants.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");
    …
    

    A couple of things to note:

    • 我必须重新定义 .m 文件中的宏 after #undef ,以便使用宏 .

    • 我还必须使用 #include 而不是 #import 才能正常工作并避免编译器看到以前预编译的值 .

    • 无论何时更改任何值,都需要重新编译PCH(可能还有整个项目),如果它们正常分开(并重复),则不需要重新编译 .

    希望对某人有所帮助 .

  • 50

    我自己有一个 Headers 专门用于声明用于首选项的常量NSStrings,如下所示:

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

    然后在随附的.m文件中声明它们:

    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";
    

    这种方法对我很有帮助 .

    编辑:请注意,如果在多个文件中使用字符串,这将最有效 . 如果只有一个文件使用它,则可以在使用该字符串的.m文件中执行 #define kNSStringConstant @"Constant NSString" .

  • 12
    // Prefs.h
    extern NSString * const RAHUL;
    
    // Prefs.m
    NSString * const RAHUL = @"rahul";
    
  • 14

    正如Abizer所说,你可以将它放入PCH文件中 . 另一种不那么脏的方法是为所有密钥创建一个包含文件,然后将其包含在您正在使用密钥的文件中,或者将其包含在PCH中 . 将它们放在自己的包含文件中,即至少为您提供了一个查找和定义所有这些常量的地方 .

  • 11

    如果你想要像全局常量那样的东西;一种快速的方法是将常量声明放入 pch 文件中 .

  • 7

    我使用单例类,以便我可以模拟类并在必要时更改常量以进行测试 . 常量类看起来像这样:

    #import <Foundation/Foundation.h>
    
    @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
    
  • 117

    尝试使用类方法:

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

    我有时会用它 .

  • 7

    如果你喜欢名称空间常量,你可以利用struct,Friday Q&A 2011-08-19: Namespaced Constants and Functions

    // 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"
    };
    

相关问题