Objective-C中的常量

1048
我正在开发一个Cocoa应用程序,使用常量NSString作为存储首选项键名的方法。
我知道这是一个好主意,因为它允许在必要时轻松更改键。
此外,这是“将数据与逻辑分离”的整体概念。
无论如何,有没有一种好的方法可以使这些常量为整个应用程序定义一次?
我相信有一种简单而聪明的方法,但现在我的类只是重新定义它们使用的那些常量。

8
面向对象编程(OOP)是将数据和逻辑组合在一起的编程范式。您提出的建议只是一种良好的编程实践,即使程序变得更易于修改。 - khatchad
14个回答

10

如果你喜欢命名空间常量,可以利用结构体,Friday Q&A 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"
};

1
太好了!但是在ARC下,您需要在结构声明中为所有变量添加__unsafe_unretained限定符才能使其正常工作。 - Cemen

9

尝试使用类方法:

+(NSString*)theMainTitle
{
    return @"Hello World";
}

我有时会使用它。


7
一个类方法不是一个常量。它在运行时有一个成本,并且可能不总是返回相同的对象(如果您实现了这样的方式,它将是如此,但您不一定已经以这种方式实现),这意味着您必须使用isEqualToString:进行比较,这又是运行时进一步的成本。当您想要常量时,请创建常量。 - Peter Hosey
2
@Peter Hosey,您的评论是正确的,但在“高级”编程语言(如Ruby)中,我们每行代码都会承担一次或多次这样的性能损失,而不必担心它。我并不是说您不正确,而只是评论不同“世界”之间标准的差异。 - Dan Rosenstark
1
Ruby中的True。大多数人编写的性能对于典型应用程序来说是相当不必要的。 - Peter DeWeese

7
我使用单例模式,这样我就可以模拟该类并在需要进行测试时更改常量。 常量类看起来像这样:
#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

1
如果你想从 Objective-C 调用类似 NSString.newLine; 的东西,并且希望它是静态常量,你可以在 Swift 中创建类似以下的东西:
public extension NSString {
    @objc public static let newLine = "\n"
}

你有一个漂亮易读的常量定义,可以在你选择的类型内使用,同时仍然受到类型上下文的限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接