我有一个Objective-c“工具”(控制台)程序,可以在运行时动态加载objective-c bundle。一些bundle文件共享来自同一框架的类,所以我得到了“将两个实现的类”消息转储到控制台。
它不会阻止任何工作,但在控制台上显示消息有点烦人。有没有办法防止它们被丢弃?是否有一种方法可以更改捆绑包,因此它们不会编译/链接相同的类?
答案 0 :(得分:3)
我以前一直在这艘船上,并不是一艘好船。我花了很长时间投资最好的方法来避免运行时类名称冲突。解决方案是:
创建一个预构建脚本,用于解析头文件中的所有@interface
声明,并获取所有类名。此脚本生成一个新标头,其中包含以下内容:
#define MyClass MyClass_Target
#define MyOtherClass MyOtherClass_Target
#define MyThirdClass MyThirdClass_Target
(显然,_Target
后缀是由您的预构建脚本能够查看和使用的构建参数设置的。
该脚本可以是Perl或Python脚本,只扫描*.h
之后提取单词的每个@interface
文件。
将构建配置为自动包含生成的头文件,这样您就不必在每个源文件中手动包含生成的头。
如果您的捆绑包有笔尖,它会增加额外的复杂性,但仍然可以完成。创建另一个替换现有“Nib编译器”的脚本。这个程序基本上执行相同的类重命名,但对于nib(它很容易,因为nib文件是XML)。我不记得在哪里设置它,但在Xcode中有一个位置允许您选择如何“编译”Nib文件。您的nib编译器脚本基本上是一个包装器,它重命名nib中的类,然后调用真正的nib编译器(您可以通过查看构建日志来了解它是如何调用的)。
是的,即使在调试情况下,它的效果也非常好。当您点击断点时,Xcode会显示类的名称及其目标后缀,因此您知道自己所在的捆绑包,尽管源代码显示的内容不同。 “修复&继续“尽我所能地工作。
另外,因为类重命名是在编译时之前完成的,所以它不会影响源代码版本控制,与Interface Builder的交互等等。
动态生成的类名不起作用,例如从Class
返回的NSClassFromString
个对象,除非代码知道必要的后缀。
这种复杂的设置需要一些维护。一旦我完成并运行它就能很好地满足我们的需求,但是它时不时需要进行调整才能保证它的顺利运行。
答案 1 :(得分:3)
如果它们是不同的实现,请使用唯一的前缀。
如果它们是相同的实现并且只是由多个图像导出,请重新配置目标,使其仅导出一个。
具体做法是:
是否有一种方法可以更改捆绑包,因此它们不会编译/链接相同的类?
将这些共享类放在一个单独的框架中,不要将它们作为bundle的一部分进行编译 - 只需将bundle链接到共享的框架即可。
答案 2 :(得分:0)
您是否尝试过仅将共享类的标头(@interface
s)添加到软件包中(以便编译器知道API),而不是代码文件(@implementation
s)?
由于您要链接一个包,链接器(ld
)不应该抱怨它找不到给定类的实现 - 它会将此任务委托给动态链接器( dyld
)一旦你在主程序中加载了bundle就会启动它。然后dyld
应该自动在bundle和program之间建立必需的引用。
答案 3 :(得分:0)
如果您是插件包的开发者,您可以将-undefined dynamic_lookup作为其他链接器标志传递,并从插件中删除所有库中的所有库(在主二进制文件和插件中)