我认为编译器可以在编译时标记对类别定义的方法的调用(它知道它们是在一个类别中定义的,而不是主类,因为原型在@interface Class(Category)部分) – 因此可以构建一个表中的对象文件中的“外部类别方法”.然后,链接器在进行其正常链接后,应该能够连接/合并并处理来自所有对象的“外部类别方法”表,并在所有链接的框架/库/对象中查找匹配的类类别中的匹配符号,然后可以拉出那些还没有在目标中的那些.
必须有一些我失踪的东西,但它是什么呢?为什么这不可能?
解决方法@H_403_8@
链接器将静态库像一个大的随机片段集合一样处理,它将从其中抽取单个片段来完成来自链接单元的其余部分的任何符号请求.
即如果主程序调用_foo和_foo只出现在静态库中,那么_foo以及任何从属符号将被拖入.
但是,当您调用类别中的方法时,由于Objective-C的活力,没有特定的符号引用.
-ObjC标志告诉链接器,因为这样,它应该从静态库中抓取所有类别,并将’em’放入主二进制文件中.
这有点令人困惑,假设编译器应该更加聪明(而且确实应该在开发工具层面上提供帮助).记住几件事很重要:
>在头文件中声明的任何东西在链接器滚动的时候都会丢失.符号由编译单元创建,而不是头文件.标题文件几乎产生了一个承诺,一个符号将被稍后或链接实现的具体创建,但是不能在自己内部创建一个符号(或者每个编译单元 – 每个.o – 将最终得到一个在链接时间会出现符号和兴趣.
Objective-C是完全动态的.当你说[(id)foo bar]时,唯一的要求是该条在某个地方被定义.如果它实际上是完全实现的(直到运行时),这并不重要.
>类别不必具有相应的@implementations;可以使用类别来声明方法可能存在,实际上在将@optional添加到@protocol之前,通常在NSObject(ewwww)上使用没有@implementation的类别来表示“嘿,这个可选方法可能存在于运行时“.
>编译和链接是完全独立的过程.编译是关于扩展代码并将其转换为可执行字节库.链接是关于使用这些库并把它们放在一起可以实际运行的东西,包括解决库之间的所有依赖关系.编译器并不知道有什么可能被链接,并且链接器没有关于可能定义了哪些东西(没有产生硬符号)的信息.
最终结果?
链接器没有足够的信息来解析依赖关系.
即如果主程序调用_foo和_foo只出现在静态库中,那么_foo以及任何从属符号将被拖入.
但是,当您调用类别中的方法时,由于Objective-C的活力,没有特定的符号引用.
-ObjC标志告诉链接器,因为这样,它应该从静态库中抓取所有类别,并将’em’放入主二进制文件中.
这有点令人困惑,假设编译器应该更加聪明(而且确实应该在开发工具层面上提供帮助).记住几件事很重要:
>在头文件中声明的任何东西在链接器滚动的时候都会丢失.符号由编译单元创建,而不是头文件.标题文件几乎产生了一个承诺,一个符号将被稍后或链接实现的具体创建,但是不能在自己内部创建一个符号(或者每个编译单元 – 每个.o – 将最终得到一个在链接时间会出现符号和兴趣.
Objective-C是完全动态的.当你说[(id)foo bar]时,唯一的要求是该条在某个地方被定义.如果它实际上是完全实现的(直到运行时),这并不重要.
>类别不必具有相应的@implementations;可以使用类别来声明方法可能存在,实际上在将@optional添加到@protocol之前,通常在NSObject(ewwww)上使用没有@implementation的类别来表示“嘿,这个可选方法可能存在于运行时“.
>编译和链接是完全独立的过程.编译是关于扩展代码并将其转换为可执行字节库.链接是关于使用这些库并把它们放在一起可以实际运行的东西,包括解决库之间的所有依赖关系.编译器并不知道有什么可能被链接,并且链接器没有关于可能定义了哪些东西(没有产生硬符号)的信息.
最终结果?
链接器没有足够的信息来解析依赖关系.