为了账号安全,请及时绑定邮箱和手机立即绑定

解决Objective-C命名空间冲突的最佳方法是什么?

解决Objective-C命名空间冲突的最佳方法是什么?

回首忆惘然 2019-08-06 14:07:19
解决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中是否有类似的可能性,如果没有,是否还有其他聪明,棘手的解决方案可以使用解析命名空间冲突?有任何想法吗?更新:只是为了澄清这一点:建议如何提前避免命名空间冲突或如何创建更好的命名空间的答案当然是受欢迎的; 但是,我不会接受它们作为答案,因为它们不能解决我的问题。我有两个库和它们的类名冲突。我无法改变它们; 我没有任何一个的来源。碰撞已经存在,如何提前避免它的提示将不再有用。我可以将它们转发给这些框架的开发人员,并希望他们在未来选择更好的命名空间,但目前我正在寻找一个解决方案,以便在单个应用程序中使用框架。任何可能的解决方案?
查看完整描述

3 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

如果您不需要同时使用两个框架中的类,并且您的目标是支持NSBundle卸载的平台(OS X 10.4或更高版本,没有GNUStep支持),并且性能对您来说确实不是问题,我相信你可以在每次需要使用一个类时加载一个框架,然后在需要使用其他框架时卸载它并加载另一个框架。

我最初的想法是使用NSBundle加载其中一个框架,然后复制或重命名该框架内的类,然后加载另一个框架。这有两个问题。首先,我找不到复制指向重命名或复制类的数据的函数,而第一个框架中引用重命名类的任何其他类现在将从其他框架引用该类。

如果有方法可以复制IMP指向的数据,则无需复制或重命名类。您可以创建一个新类,然后复制ivars,方法,属性和类别。还有更多的工作,但这是可能的。但是,您仍然会遇到引用错误类的框架中的其他类的问题。

编辑:C和Objective-C运行时之间的根本区别在于,据我所知,当加载库时,这些库中的函数包含指向它们引用的任何符号的指针,而在Objective-C中,它们包含字符串表示形式。 thsoe符号的名称。因此,在您的示例中,您可以使用dlsym在内存中获取符号的地址并将其附加到另一个符号。库中的其他代码仍然有效,因为您没有更改原始符号的地址。Objective-C使用查找表将类名映射到地址,并且它是1-1映射,因此您不能拥有两个具有相同名称的类。因此,要加载这两个类,其中一个必须更改其名称。但是,当其他类需要访问其中一个具有该名称的类时,


查看完整回答
反对 回复 2019-08-06
?
叮当猫咪

TA贡献1776条经验 获得超12个赞

使用唯一前缀为您的类添加前缀基本上是唯一的选择,但有几种方法可以减少繁琐和丑陋。还有就是选择一个长时间的讨论在这里。我最喜欢的是@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

作为完整策略的一部分,您可以为所有类添加前缀,例如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)一起使用。


查看完整回答
反对 回复 2019-08-06
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

有些人已经分享了一些可能有助于解决问题的棘手和聪明的代码。一些建议可能有效,但所有这些建议都不太理想,其中一些建议非常难以实施。(有时丑陋的黑客是不可避免的,但我尽量避免使用它们。)从实际的角度来看,这是我的建议。

  1. 无论如何,请告知开发人员冲突的两个框架,并明确表示他们未能避免和/或处理冲突会导致您遇到真正的业务问题,如果解决这个问题,可能会导致业务收入损失。强调虽然在每个类的基础上解决现有的冲突是一个不那么具有侵入性的解决方案,但是完全改变它们的前缀(或者如果它们当前不是,那么使用它们,并且对它们感到羞耻!)是确保它们不会的最佳方法。再次看到同样的问题。

  2. 如果命名冲突仅限于一组相当小的类,请查看是否可以解决这些类,特别是如果您的代码之一未直接或间接使用其中一个冲突类。如果是,请查看供应商是否将提供不包含冲突类的框架的自定义版本。如果没有,请坦率地说,他们缺乏灵活性会降低您使用框架的投资回报率。不要因为在合理范围内咄咄逼人而感到沮丧 - 客户永远是对的。;-)

  3. 如果一个框架更“可有可无”,您可以考虑将其替换为另一个框架(或代码组合),无论是第三方还是自制程序。(后者是不受欢迎的最坏情况,因为它肯定会产生额外的业务成本,无论是开发还是维护。)如果你这样做,请告知该框架的供应商你决定不使用他们的框架的原因。

  4. 如果两个框架被认为对您的应用程序同样不可或缺,请探索将其中一个框架的使用分解为一个或多个单独进程的方法,也许可以通过DO进行通信,如Louis Gerbarg建议的那样。根据沟通的程度,这可能没有你想象的那么糟糕。我相信有几个程序(包括QuickTime)使用这种方法通过在Leopard中使用Seatbelt沙箱配置文件提供更细粒度的安全性,这样只允许代码的特定子集执行关键或敏感操作。性能将是一种权衡,但可能是您唯一的选择

我猜测许可费,条款和持续时间可能会阻止对这些点的即时行动。希望您能够尽快解决冲突。祝好运


查看完整回答
反对 回复 2019-08-06
  • 3 回答
  • 0 关注
  • 1818 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信