在objective-c中定义一个常量

时间:2009-06-29 18:22:08

标签: objective-c constants

我想在objective-c中定义一个常量。

以前我有以下功能:

+(NSString *) getDocumentsDir {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
    NSString *documentsDir = [paths objectAtIndex: 0];
    paths = nil;
    return documentsDir;
}

我只想定义一个常量“Documents_Dir” - 当函数被调用时,之后才能访问以前创建的值。

我尝试过以下代码,但无效:

#define getDocumentsDir \
{   \
#ifdef Documents_Dir    \
return Documents_Dir;   \
#else   \
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);  \
NSString *documentsDir = [paths objectAtIndex: 0];  \
#define Documents_Dir [paths objectAtIndex: 0]; \
paths = nil;    \
return Documents_Dir;   \
#endif  \
}   \

我对预编译器指令不太满意,所以任何帮助都将受到赞赏。

3 个答案:

答案 0 :(得分:34)

序言:理解预编译器指令和真实常量之间的区别是值得的。 #define只是在编译器构建代码之前进行文本替换。这对于数值常量和typedef很有用,但对于函数或方法调用并不总是最好的想法。我假设你真的想要一个真正的常量,这意味着创建搜索路径的代码应该只执行一次。


MyClass.m 文件中,定义变量并将其填入 +initialize 方法,如下所示:

static NSArray *documentsDir;

@implementation MyClass

+ (void) initialize {
    if (documentsDir == nil) {
        documentsDir = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES) lastObject] retain];
    }
}

...

@end

static 修饰符使其仅在声明它的编译单元中可见。对于一个简单的常数,这就是你所需要的。

如果类具有子类,则每个子类将调用+initialize一次(默认情况下),因此在分配给documentsDir之前,您需要检查nil是否为==,所以你不要泄漏内存。 (或者,正如Peter Lewis指出的那样,您可以使用extern-isMemberOfClass:方法检查当前正在初始化的类是否为MyClass。)如果子类还需要直接访问常量,您需要在 MyClass.h 文件(子类包含的)中将变量预先声明为extern NSArray *documentsDir; @interface MyClass : NSObject ... @end

static

如果您将变量预先声明为extern,则必须从定义中删除extern关键字以避免编译错误。这是必要的,因此变量可以跨越多个编译单元。 (啊,C的乐趣......)

注意:在Objective-C代码中,将某些内容声明为OBJC_EXPORT的更好方法是使用 #define (a {{1在<objc/objc-api.h>)中声明的,它是根据您是否使用C ++设置的。只需将extern替换为OBJC_EXPORT即可。


编辑:我刚刚遇到related SO question

答案 1 :(得分:12)

最简单的解决方案是将路径更改为静态变量,并仅将其评估一次,如下所示:

+(NSString *) getDocumentsDir {
    static NSString *documentsDir = nil;
    if ( !documentsDir ) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
        documentsDir = [paths objectAtIndex: 0];
    }
    return documentsDir;
}

“static”告诉编译器documentsDir实际上是一个全局变量,尽管只能在函数内访问。因此它被初始化为nil,并且第一次调用getDocumentsDir将重新评估它,然后进一步调用将返回预先评估的值。

答案 2 :(得分:1)

关于Peter N Lewis代码的小优化:

-(NSString *) documentsDir {
    static NSString *documentsDir = nil;
    return documentsDir ?: (documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);
}