我正在开发一个Cocoa应用程序,我使用常量nsstring作为存储我的首选项的键名的方式。
我知道这是一个好主意,因为它允许在必要时轻松更改密钥。 此外,这是整个“将数据与逻辑分离”的概念。
不管怎样,有没有一种好方法让这些常量在整个应用程序中定义一次?
我相信有一种简单而聪明的方法,但现在我的类只是重新定义它们所使用的方法。
我正在开发一个Cocoa应用程序,我使用常量nsstring作为存储我的首选项的键名的方式。
我知道这是一个好主意,因为它允许在必要时轻松更改密钥。 此外,这是整个“将数据与逻辑分离”的概念。
不管怎样,有没有一种好方法让这些常量在整个应用程序中定义一次?
我相信有一种简单而聪明的方法,但现在我的类只是重新定义它们所使用的方法。
当前回答
我使用了一个单例类,这样我就可以模拟该类并在测试时更改常量。常量类是这样的:
#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
其他回答
我使用了一个单例类,这样我就可以模拟该类并在测试时更改常量。常量类是这样的:
#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
你应该创建一个像这样的头文件:
// 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";
常量。应该将M添加到应用程序/框架的目标中,以便将其链接到最终产品中。
使用字符串常量而不是#define'd常量的优点是,你可以使用指针比较(stringInstance == MyFirstConstant)来测试是否相等,这比字符串比较([stringInstance isEqualToString:MyFirstConstant])快得多(并且更容易阅读,IMO)。
正如Abizer所说,您可以将其放入PCH文件中。另一种不那么脏的方法是为所有键创建一个包含文件,然后将其包含在您使用键的文件中,或者将其包含在PCH中。在它们自己的包含文件中,至少给了您一个查找和定义所有这些常量的地方。
简单的方法:
// 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";
第二种方法的一个好处是,改变常量的值不会导致整个程序的重新构建。
// Prefs.h
extern NSString * const RAHUL;
// Prefs.m
NSString * const RAHUL = @"rahul";