Objective-C 没有命名空间;它很像 C,一切都在一个全局命名空间中。通常的做法是在类前面加上首字母,例如如果您在 IBM 工作,您可以在他们前面加上“IBM”;如果你为微软工作,你可以使用“MS”;等等。有时首字母指的是项目,例如Adium 以“AI”作为类的前缀(因为它背后没有公司可以使用缩写)。 Apple 为类加上 NS 前缀,并表示此前缀仅供 Apple 使用。
到目前为止一切顺利。但是在前面的类名后面附加 2 到 4 个字母是一个非常非常有限的命名空间。例如。 MS 或 AI 可能具有完全不同的含义(例如 AI 可能是人工智能),其他一些开发人员可能决定使用它们并创建一个同名的类。 砰,命名空间冲突。
好的,如果这是您自己的一个类和您正在使用的外部框架之一之间的冲突,您可以轻松更改您的类的命名,没什么大不了的。 但是,如果您使用两个外部框架,这两个框架您都没有源代码并且无法更改,该怎么办?您的应用程序与它们都链接,并且您会遇到名称冲突。你将如何解决这些问题?以您仍然可以使用这两个类的方式解决它们的最佳方法是什么?
在 C 中,您可以通过不直接链接到库来解决这些问题,而是在运行时使用 dlopen() 加载库,然后使用 dlsym() 找到您要查找的符号并将其分配给全局符号(你可以用任何你喜欢的方式命名),然后通过这个全局符号访问它。例如。如果你因为某个 C 库有一个名为 open() 的函数而发生冲突,你可以定义一个名为 myOpen 的变量并让它指向库的 open() 函数,这样当你想使用系统 open() 时,您只需使用 open(),当您想使用另一个时,您可以通过 myOpen 标识符访问它。
在 Objective-C 中是否有类似的可能,如果没有,是否有任何其他聪明、棘手的解决方案可以用来解决命名空间冲突?有什么想法吗?
只是为了澄清这一点:当然欢迎建议如何提前避免命名空间冲突或如何创建更好的命名空间的答案;但是,我不会接受它们作为答案,因为它们不能解决我的问题。我有两个库,它们的类名发生冲突。我无法改变它们;我没有任何一个的来源。碰撞已经存在,关于如何提前避免碰撞的提示将不再有帮助。我可以将它们转发给这些框架的开发人员,并希望他们将来选择更好的命名空间,但目前我正在寻找一种解决方案,以便现在在单个应用程序中使用这些框架。有什么解决方案可以做到这一点?
最佳答案
为你的类添加一个唯一的前缀基本上是唯一的选择,但有几种方法可以减少繁琐和丑陋。关于选项的讨论很长here .我最喜欢的是 @compatibility_alias
Objective-C 编译器指令(描述为 here)。您可以使用 @compatibility_alias
来“重命名”一个类,允许您使用 FQDN 或类似的前缀来命名您的类:
@interface COM_WHATEVER_ClassName : NSObject
@end
@compatibility_alias ClassName COM_WHATEVER_ClassName
// now ClassName is an alias for COM_WHATEVER_ClassName
@implementation ClassName //OK
//blah
@end
ClassName *myClass; //OK
作为完整策略的一部分,您可以为所有类添加一个唯一前缀,例如 FQDN,然后使用所有 @compatibility_alias
创建一个 header (我想您可以自动生成说标题)。
这样的前缀的缺点是,除了编译器之外,您必须在任何需要来自字符串的类名的地方输入真正的类名(例如上面的 COM_WHATEVER_ClassName
)。值得注意的是,@compatibility_alias
是编译器指令,而不是运行时函数,因此 NSClassFromString(ClassName)
会失败(返回 nil
)——你会必须使用 NSClassFromString(COM_WHATERVER_ClassName)
。您可以通过构建阶段使用 ibtool
来修改 Interface Builder nib/xib 中的类名,这样您就不必在 Interface Builder 中编写完整的 COM_WHATEVER_...。
最后警告:因为这是一个编译器指令(而且是一个晦涩难懂的指令),它可能无法跨编译器移植。特别是,我不知道它是否适用于 LLVM 项目的 Clang 前端,尽管它应该适用于 LLVM-GCC(LLVM 使用 GCC 前端)。
https://stackoverflow.com/questions/178434/