I want to define a constant in objective-c.
我想在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.
我只需要定义一个常量“Documents_Dir”一次——当函数被调用时,然后访问一个先前创建的值。
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.
我不擅长预编译指令,所以任何帮助都会受到感激。
3 个解决方案
#1
34
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.
序曲:理解预编译指令和真正的常量之间的区别是有好处的。#define只是在编译器构建代码之前进行文本替换。这对于数值常量和typedefs来说非常有用,但对于函数或方法调用来说并不总是最好的方法。我在假设您确实需要一个真正的常量,这意味着创建搜索路径的代码应该只执行一次。
In your MyClass.m file, define the variable and populate it in an +initialize
method like so:
在你MyClass。m文件,定义变量并用+initialize方法进行填充,如下所示:
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):
如果类有子类,那么对于每个子类(默认情况下)将会调用一次+初始化,所以在分配给它之前,您需要检查documentsDir是否为nil,这样就不会泄漏内存。(或者,正如Peter Lewis指出的,您可以使用==或-isMemberOfClass:方法检查当前正在初始化的类是否是MyClass。)如果子类也需要直接访问常量,则需要在MyClass中将变量预先声明为extern。h文件(子类包括):
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...)
如果将变量预先声明为extern,则必须从定义中删除静态关键字,以避免编译错误。这是必要的,这样变量就可以跨多个编译单元。(啊,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.
注意:在Objective-C代码中,声明外部内容的更好方法是使用OBJC_EXPORT(在
Edit: I just happened upon a related SO question.
编辑:我碰巧遇到了一个与SO相关的问题。
#2
12
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.
“静态”告诉编译器documentsDir实际上是一个全局变量,尽管只能在函数中访问。初始化为nil,对getDocumentsDir的第一个调用将对其进行求值,然后进一步的调用将返回预求值。
#3
1
Small optimization regarding Peter N Lewis code:
关于Peter N Lewis代码的小优化:
-(NSString *) documentsDir {
static NSString *documentsDir = nil;
return documentsDir ?: (documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);
}
#1
34
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.
序曲:理解预编译指令和真正的常量之间的区别是有好处的。#define只是在编译器构建代码之前进行文本替换。这对于数值常量和typedefs来说非常有用,但对于函数或方法调用来说并不总是最好的方法。我在假设您确实需要一个真正的常量,这意味着创建搜索路径的代码应该只执行一次。
In your MyClass.m file, define the variable and populate it in an +initialize
method like so:
在你MyClass。m文件,定义变量并用+initialize方法进行填充,如下所示:
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):
如果类有子类,那么对于每个子类(默认情况下)将会调用一次+初始化,所以在分配给它之前,您需要检查documentsDir是否为nil,这样就不会泄漏内存。(或者,正如Peter Lewis指出的,您可以使用==或-isMemberOfClass:方法检查当前正在初始化的类是否是MyClass。)如果子类也需要直接访问常量,则需要在MyClass中将变量预先声明为extern。h文件(子类包括):
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...)
如果将变量预先声明为extern,则必须从定义中删除静态关键字,以避免编译错误。这是必要的,这样变量就可以跨多个编译单元。(啊,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.
注意:在Objective-C代码中,声明外部内容的更好方法是使用OBJC_EXPORT(在
Edit: I just happened upon a related SO question.
编辑:我碰巧遇到了一个与SO相关的问题。
#2
12
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.
“静态”告诉编译器documentsDir实际上是一个全局变量,尽管只能在函数中访问。初始化为nil,对getDocumentsDir的第一个调用将对其进行求值,然后进一步的调用将返回预求值。
#3
1
Small optimization regarding Peter N Lewis code:
关于Peter N Lewis代码的小优化:
-(NSString *) documentsDir {
static NSString *documentsDir = nil;
return documentsDir ?: (documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);
}