我正在开发一个Cocoa应用程序,我使用常量nsstring作为存储我的首选项的键名的方式。

我知道这是一个好主意,因为它允许在必要时轻松更改密钥。 此外,这是整个“将数据与逻辑分离”的概念。

不管怎样,有没有一种好方法让这些常量在整个应用程序中定义一次?

我相信有一种简单而聪明的方法,但现在我的类只是重新定义它们所使用的方法。


当前回答

如果你想调用nsstring。newline;从objective c,你想要它是静态常量,你可以在swift中创建这样的东西:

public extension NSString {
    @objc public static let newLine = "\n"
}

这样你就有了很好的可读的常量定义,并且可以从你选择的类型中获得,同时还可以绑定到类型的上下文。

其他回答

还有一件事要提一下。如果你需要一个非全局常量,你应该使用static关键字。

例子

// In your *.m file
static NSString * const kNSStringConst = @"const value";

因为static关键字,这个const在文件外部是不可见的。


@QuinnTaylor的小修正:静态变量在编译单元中是可见的。通常,这是一个单独的.m文件(如本例所示),但是如果你在包含在其他地方的头文件中声明它,它会咬你一口,因为编译后你会得到链接器错误

如果你喜欢命名空间常量,你可以使用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"
};

你应该创建一个像这样的头文件:

// 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)。

如果你想调用nsstring。newline;从objective c,你想要它是静态常量,你可以在swift中创建这样的东西:

public extension NSString {
    @objc public static let newLine = "\n"
}

这样你就有了很好的可读的常量定义,并且可以从你选择的类型中获得,同时还可以绑定到类型的上下文。

我使用了一个单例类,这样我就可以模拟该类并在测试时更改常量。常量类是这样的:

#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