Mec*_*cki 174 macos cocoa namespaces objective-c
Objective-C没有名称空间; 它很像C,一切都在一个全局命名空间内.通常的做法是使用首字母为类添加前缀,例如,如果您在IBM工作,则可以在前面加上"IBM"; 如果你在微软工作,你可以使用"MS"; 等等.有时首字母引用项目,例如Adium前缀带有"AI"的类(因为没有公司可以使用缩写).Apple使用NS作为前缀类,并说这个前缀仅供Apple使用.
到目前为止一切顺利.但是在前面添加2到4个字母到一个类名是一个非常非常有限的命名空间.例如,MS或AI可能具有完全不同的含义(例如,AI可能是人工智能),而其他一些开发人员可能决定使用它们并创建一个同名的类.Bang,命名空间冲突.
好吧,如果这是你自己的一个类和你正在使用的外部框架之间的冲突,你可以轻松地改变你的类的命名,没什么大不了的.但是如果你使用两个外部框架,那么你没有源代码的框架和你无法改变的框架呢?您的应用程序与它们都链接,并且您会收到名称冲突.你会如何解决这些问题?以这样的方式解决它们的最佳方法是什么,你仍然可以使用这两个类?
在C中,您可以通过不直接链接到库来解决这些问题,而是使用dlopen()在运行时加载库,然后使用dlsym()找到您要查找的符号并将其分配给全局符号(即可以任何你喜欢的方式命名)然后通过这个全局符号访问它.例如,如果您遇到冲突,因为某个C库有一个名为open()的函数,您可以定义一个名为myOpen的变量并让它指向库的open()函数,因此当您想要使用系统open()时,你只需使用open(),当你想使用另一个时,你可以通过myOpen标识符访问它.
在Objective-C中是否有类似的可能性,如果没有,是否还有其他聪明,棘手的解决方案可以使用解析命名空间冲突?有任何想法吗?
只是为了澄清这一点:建议如何提前避免命名空间冲突或如何创建更好的命名空间的答案当然是受欢迎的; 但是,我不会接受它们作为答案,因为它们不能解决我的问题.我有两个库和它们的类名冲突.我无法改变它们; 我没有任何一个的来源.碰撞已经存在,如何提前避免它的提示将不再有用.我可以将它们转发给这些框架的开发人员,并希望他们在未来选择更好的命名空间,但目前我正在寻找一个解决方案,以便在单个应用程序中使用框架.任何可能的解决方案?
Bar*_*ark 93
使用唯一前缀为您的类添加前缀基本上是唯一的选择,但有几种方法可以减少繁琐和丑陋.还有就是选择一个长时间的讨论在这里.我最喜欢的是@compatibility_aliasObjective-C编译器指令(在此描述).您可以使用@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
Run Code Online (Sandbox Code Playgroud)
作为完整策略的一部分,您可以为所有类添加前缀,例如FQDN,然后创建一个包含所有内容的标头@compatibility_alias(我想您可以自动生成所述标头).
这样的前缀的缺点是你必须COM_WHATEVER_ClassName在除编译器之外的字符串中需要类名的任何东西中输入真正的类名(例如上面).值得注意的是,@compatibility_alias是一个编译器指令,而不是运行时函数,因此NSClassFromString(ClassName)将失败(返回nil) - 您将不得不使用NSClassFromString(COM_WHATERVER_ClassName).您可以使用ibtoolvia build阶段在Interface Builder nib/xib中修改类名,这样就不必在Interface Builder中编写完整的COM_WHATEVER _...
最后的警告:因为这是一个编译器指令(并且是一个模糊的指令),它可能无法跨编译器移植.特别是,我不知道它是否适用于LLVM项目的Clang前端,尽管它应该与LLVM-GCC(使用GCC前端的LLVM)一起使用.
Mic*_*ley 47
如果您不需要同时使用两个框架中的类,并且您的目标是支持NSBundle卸载的平台(OS X 10.4或更高版本,没有GNUStep支持),并且性能对您来说确实不是问题,我相信你可以在每次需要使用一个类时加载一个框架,然后在需要使用其他框架时卸载它并加载另一个框架.
我最初的想法是使用NSBundle加载其中一个框架,然后复制或重命名该框架内的类,然后加载另一个框架.这有两个问题.首先,我找不到复制指向重命名或复制类的数据的函数,而第一个框架中引用重命名类的任何其他类现在将从其他框架引用该类.
如果有方法可以复制IMP指向的数据,则无需复制或重命名类.您可以创建一个新类,然后复制ivars,方法,属性和类别.还有更多的工作,但这是可能的.但是,您仍然会遇到引用错误类的框架中的其他类的问题.
编辑:C和Objective-C运行时之间的根本区别在于,我理解,库被加载时,在这些库中的功能包含指向它们所引用的任何符号,而在Objective-C,它们包含的字符串表示thsoe符号的名称.因此,在您的示例中,您可以使用dlsym在内存中获取符号的地址并将其附加到另一个符号.库中的其他代码仍然有效,因为您没有更改原始符号的地址.Objective-C使用查找表将类名映射到地址,并且它是1-1映射,因此您不能拥有两个具有相同名称的类.因此,要加载这两个类,其中一个必须更改其名称.但是,当其他类需要访问其中一个具有该名称的类时,
Qui*_*lor 12
有些人已经分享了一些可能有助于解决问题的棘手和聪明的代码.一些建议可能有效,但所有这些建议都不太理想,其中一些建议非常难以实施.(有时丑陋的黑客是不可避免的,但我尽量避免使用它们.)从实际的角度来看,这是我的建议.
我猜测许可费,条款和持续时间可能会阻止对这些点的即时行动.希望您能够尽快解决冲突.祝好运!
这很糟糕,但您可以使用分布式对象,以便只将一个类保留在从属程序地址和RPC中.如果你来回传递大量的东西(如果两个类都直接操纵视图等可能不可能),那将会变得混乱.
还有其他潜在的解决方案,但其中很多都取决于具体情况.特别是,您使用的是现代或旧版运行时,是胖还是单一架构,32或64位,您定位的操作系统版本,动态链接,静态链接,或者您有选择权,是否可能可以做一些可能需要维护新软件更新的东西.
如果你真的很绝望,你可以做的是:
以上将是相当费力的,如果你需要针对多个arch和不同的运行时版本实现它,它将是非常不愉快的,但它肯定可以工作.
| 归档时间: |
|
| 查看次数: |
40087 次 |
| 最近记录: |