Answers:
您应该创建一个头文件,例如
// 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更易于阅读)。
NSString
用copy
而不是定义其属性的类retain
。这样,它们可能(并且应该)持有您NSString*
常量的其他实例,并且直接内存地址比较将失败。另外,我假设任何合理的最佳实现-isEqualToString:
都会在进入字符比较的本质之前检查指针是否相等。
最简单的方法:
// 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";
第二个好处是,更改常量的值不会导致整个程序的重建。
extern NSString const * const MyConstant
,即使其成为指向常量对象的常量指针,而不只是常量指针?
还有一件事要提。如果需要非全局常量,则应使用static
关键字。
例
// In your *.m file
static NSString * const kNSStringConst = @"const value";
由于有static
关键字,此const在文件外部不可见。
通过@QuinnTaylor进行的较小校正:静态变量在编译单元中可见。通常,这是一个.m文件(如本例所示),但如果在其他位置包含的标头中声明它,它可能会咬住您,因为编译后会出现链接器错误
公认的(正确的)答案是:“您可以将此[Constants.h]文件...包括在项目的预编译头中。”
作为新手,我很难在没有进一步说明的情况下执行此操作-方法如下:在YourAppNameHere-Prefix.pch文件(这是Xcode中预编译标头的默认名称)中,将Constants.h导入到#ifdef __OBJC__
block中。
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "Constants.h"
#endif
另请注意,Constants.h和Constants.m文件中绝对不应包含任何其他内容,除非接受的答案中有描述。(无接口或实现)。
我通常使用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"
等,我仅在.h文件中拥有有关常量的所有信息。
我自己有一个标头,用于声明用于首选项的常量NSString,如下所示:
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";
这种方法对我很有帮助。
编辑:请注意,如果在多个文件中使用了字符串,则此方法效果最好。如果只有一个文件使用它,则可以#define kNSStringConstant @"Constant NSString"
在使用该字符串的.m文件中进行操作。
对@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");
…
需要注意的几件事:
我不得不重新定义宏.m
文件后, #undef
荷兰国际集团它的宏观使用。
我还必须使用#include
代替它,#import
以使其正常工作,并避免编译器看到以前预编译的值。
每当更改任何值时,都需要重新编译您的PCH(可能还有整个项目),而如果正常分开(并重复)它们,则情况并非如此。
希望对某人有帮助。
extern
以上内容替换为,它们将完全相同FOUNDATION_EXPORT
。
尝试使用类方法:
+(NSString*)theMainTitle
{
return @"Hello World";
}
我有时会用它。
isEqualToString:
用于比较,即在运行时产生进一步的成本。当您需要常量时,请创建常量。
如果您喜欢命名空间常量,则可以利用struct,星期五问答,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"
};
__unsafe_unretained
限定符以使其起作用。
我使用单例类,以便可以模拟该类并根据需要更改常量以进行测试。常量类如下所示:
#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