链接器将静态库视为一大堆旧的随机片段集合,它将从中提取单个片段来满足来自链接单元其余部分的任何符号请求。
即如果主程序调用_foo
并且_foo
只出现在静态库中,那么 将_foo
连同任何依赖符号一起被拖入。
但是,当您调用类别中的方法时,由于 Objective-C 的动态性,没有特定的符号引用。
该-ObjC
标志告诉链接器,因此,它应该从静态库中获取所有类别并将它们放入主二进制文件中。
这有点令人困惑,并且假设编译器应该对此更聪明(并且可以肯定的是,它应该在开发工具级别提供帮助)。重要的是要记住几件事:
在链接器滚动时,头文件中声明的任何内容都几乎丢失了。符号是由编译单元创建的,而不是由头文件创建的。头文件几乎生成了一个符号将在以后具体创建或由链接实现的承诺,但不能在其自身中创建符号(否则每个编译单元 - 每个 .o - 最终都会得到一个副本符号和欢闹将在链接时随之而来)。
Objective-C 是完全动态的。当您说[(id)foo bar];
时,唯一的要求是在之前的某个地方bar
定义。它是否真正实现并不重要(直到运行时)。
类别不必有对应的@implementations;类别可用于声明可能存在的方法,事实上,在添加@optional
到之前@protocol
,通常在NSObject
(ewwwwww) 上使用类别而不@implementation
说“嘿,此可选方法可能在运行时存在”。
编译和链接是完全独立的过程。编译就是扩展代码并将其转换为可执行字节库。链接就是获取这些库并将它们组合成可以实际运行的东西,包括解决库之间的所有依赖关系。编译器并不真正知道如何链接某些东西,并且链接器没有任何关于可能已经定义的东西(没有产生硬符号)的信息。
最终结果?
链接器没有足够的信息来解决依赖关系。