在objective-c协议中定义字符串常量的最佳方法是什么?

时间:2009-12-08 11:33:51

标签: objective-c cocoa nsstring constants protocols

我已经定义了一个我的所有插件必须实现的协议。我也希望所有插件都使用某些字符串,比如MyPluginErrorDomain。使用整数这很容易在枚举中实现,但我无法弄清楚如何用字符串做同样的事情。通常,在课程中我会定义

extern NSString * const MyPluginErrorDomain;
<。>在.h文件和.m文件中:

NSString * const MyPluginErrorDomain = @"MyPluginErrorDomain";

但是这在协议中不能很好地工作,因为每个插件都必须提供自己的实现,这违背了具有常量的目的。

然后我尝试了

#define MYPLUGIN_ERROR_DOMAIN @"MyPluginErrorDomain"

但是插件中的实现类似乎看不到#define。谁知道一个好的解决方案?

4 个答案:

答案 0 :(得分:10)

您可以使用协议在标头中声明它们(但在协议接口本身之外),然后在协议的实现文件中定义它们(显然它没有@implementation部分 - 只是您的{ {1}}定义)。

或者有一个单独的.h / .m对,它只适用于字符串常量(协议头可以导入字符串常量标题)。

答案 1 :(得分:9)

你保留.h定义:

extern NSString * const MyPluginErrorDomain;

但将此部分放入一个单独的.m文件中,该文件包含在您的框架中:

NSString * const MyPluginErrorDomain = @"MyPluginErrorDomain";

所以插件仍然可以实现界面,但是在编译时,它们会在你的其他.m文件中链接或编译,所以他们会看到MyPluginErrorDomain的值。

答案 2 :(得分:3)

在C ++中,我会在这样的标题中声明它们:

const char * const MYPLUGIN_ERROR_DOMAIN = "MyPluginErrorDomain";
const char * const MYPLUGIN_FOO_DOMAIN = "MyPluginFooDomain";

请注意,由于指针是const,因此它们将是标头为#included的翻译单元的本地,因此不需要使用extern来防止多个定义错误。

答案 3 :(得分:2)

您应该将其实现为extern字符串,如示例所示:

  

extern NSString * const MyPluginErrorDomain;

或提供返回静态存储数据的extern函数。例如:

 /* h */ 

 extern NSString * MyPluginErrorDomain();

 /* m */ 

 NSString * MyPluginErrorDomain() {
    static NSString * const s = @"MyPluginErrorDomain";
    return s;
 }

原因是字符串和键经常被指针值或散列值使用和比较,而不是真正的字符串比较(isEqualToString :)。

在实施层面,:

之间存在很大差异

在代码中,这意味着当比较的字符串在多个二进制文件中定义时:

说'MyPluginErrorDomain'和'key'具有相同的字符串值,但是在不同的二进制文件中定义(即插件主机中的插件,插件中的一个)。

/////// Pointer comparison (NSString)
BOOL a = [MyPluginErrorDomain isEqualToString:key];
BOOL b = MyPluginErrorDomain == key;

// c may be false because a may be true, in that they represent the same character sequence, but do not point to the same object
BOOL c = a == b;


/////// Hash use (NSString)
// This is true
BOOL d = [MyPluginErrorDomain hash] == [key hash];

// This is indicative if true
BOOL e = [MyPluginErrorDomain hash] == [someOtherStringKey hash];

// because
BOOL f = [MyPluginErrorDomain isEqualToString:someOtherStringKey];

// g may be false (though the hash code is 'generally' correct)
BOOL g = e == f;

因此,在许多情况下需要提供密钥。这似乎是一个微不足道的观点,但很难诊断出与这种差异相关的一些问题。

散列代码和指针比较在整个Foundation和其他objc技术中用于字典存储的内部,键值编码......如果你的字典直接用于xml,这是一回事,但运行时使用是另一个,那里在实现和运行时细节中有一些注意事项。