在 Objective-c 中定义常量

发布于 2024-07-25 07:28:01 字数 815 浏览 3 评论 0原文

我想在 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  \
}   \

我对预编译器指令不强,因此任何帮助将不胜感激。

I want to define a constant in objective-c.

Previously I had the following function:

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

I'd like to define a constant "Documents_Dir" only once - when the function gets called and after that to access a previously created value.

I've tried the following code, which didn't work:

#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  \
}   \

I am not strong with precompiler directives, so any help will be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

茶花眉 2024-08-01 07:28:01

前奏:了解预编译器指令和真实常量之间的区别是值得的。 #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 指出的那样,您可以使用 ==-isMemberOfClass: 方法。)如果子类也需要直接访问常量,则需要在 MyClass.h 文件中将变量预先声明为 extern(该文件是子类包括):

extern NSArray *documentsDir;

@interface MyClass : NSObject
...
@end

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

注意: 在 Objective-C 代码中,将某些内容声明为 extern 的更好方法是使用 OBJC_EXPORT(在 中声明的 #define),根据您是否正在使用C++。 只需将 extern 替换为 OBJC_EXPORT 即可。


编辑:我刚刚偶然发现一个相关的SO问题

Prelude: It pays to understand the difference between precompiler directives and true constants. A #define just does a text replacement before the compiler builds the code. This works great for numerical constants and typedefs, but is not always the best idea for function or method calls. I'm operating under the assumption that you really want a true constant, meaning that the code to create the search path should only be executed once.


In your MyClass.m file, define the variable and populate it in an +initialize method like so:

static NSArray *documentsDir;

@implementation MyClass

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

...

@end

The static modifier makes it visible only within the compilation unit where it is declared. For a simple constant, this is all you need.

If the class has subclasses, +initialize will be called once for each subclass (by default), so you'll want to check whether documentsDir is nil before assigning to it, so you don't leak memory. (Or, as Peter Lewis points out, you can check if the class currently being initialized is the MyClass, using either == or the -isMemberOfClass: method.) If the subclasses also need to access the constant directly, you'd need to pre-declare the variable as extern in MyClass.h file (which the child classes include):

extern NSArray *documentsDir;

@interface MyClass : NSObject
...
@end

If you pre-declare the variable as extern, you must remove the static keyword from the definition to avoid compile errors. This is necessary so the variable can span multiple compilation units. (Ah, the joys of C...)

Note: In Objective-C code, the better way to declare something as extern is to use OBJC_EXPORT (a #define declared in <objc/objc-api.h>) which is set based on whether or not you're using C++. Just replace extern with OBJC_EXPORT and you're done.


Edit: I just happened upon a related SO question.

慢慢从新开始 2024-08-01 07:28:01

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

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

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

The easiest solution is to just change paths to be a static variable and evalutate it only once, like this:

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

The "static" tells the compiler that documentsDir is effectively a global variable, although only accessible within the function. So it is initialized to nil, and the first call to getDocumentsDir will evalutate it and then further calls will return the pre-evalutated value.

遇见了你 2024-08-01 07:28:01

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

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

Small optimization regarding Peter N Lewis code:

-(NSString *) documentsDir {
    static NSString *documentsDir = nil;
    return documentsDir ?: (documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文