新版本进入了测试期,时间不那么紧迫了,突然想起来之前早想读一下IQKeyboardManager的源码,现在果断走起。至于不知道IQKeyboardManager是干嘛的同学请自行搜索。
才看了一小会就遇到一行让我很不理解的代码,这行代码是在文件:IQUIWindow+Hierarchy.m中,代码如下:
IQ_LoadCategory(IQUIWindowHierarchy)
IQ_LoadCategory的定义如下:
#define IQ_LoadCategory(UNIQUE_NAME) @interface FORCELOAD_##UNIQUE_NAME :NSObject @end @implementation FORCELOAD_##UNIQUE_NAME @end
首先说明一下,##是C语言中的东西,意思是连接两个字符串,例如aa##bb, 就会得到aabb。而整个宏的意思是声明一个空得类。我就很纳闷,为什么要这么做呢?我的第一反应是难道FORCELOAD是什么预留关键字之类的?我去搜了一下,并不是。那又是为什么呢?这得从Objective-C的类别以及Objective-C的加载方式说起。说到加载方式呢又不得不说-ObjC和-all-load,-ObjC和-all-load这两个东西如果从事过一段时间ios编程的同学一定不会陌生的。至于这两个的作用是什么呢?这个又得从mac os x说起了,OS X是苹果公司系列产品开发的专属操作系统,基于UNIX系统。
下面插点其他东西(来自于网络):
静态库和动态库用UNIX 的术语来说叫做归档文件(archive 常以.a 结尾)和共享对象(share object 常以lib 开头.so 结尾)更为准确。静态库,动态库可能是WINDOWS 下的术语,但两者的概念是一样的。下面统一说静态库和动态库。
静态库,就是一大堆object (CC ,CC 在LINUX 下其实是软件链接到GCC 的,编译后默认为.o 结尾的)的集合。静态库就是用ar 等工具集合在一起。在编译的时候,连接器就会将这部分代码嵌入到目标代码里。
动态库,也是一大堆object 的集合(编译成动态或静态,只是编译选项的不同)。不同的时,在编译的时候,连接器并没有将这部分代码嵌入到目标代码里,而在运行时的时候,才加载代码。
由此,一般情况下用静态库一般都比动态库大。
说的明白一点呢就是在unix系统下,不管是静态库还是动态库都会为每个函数生成链接符号,而Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这也是OC的动态特性决定的。在OC中,当在一个静态库中使用类别来扩展已有类的时候,编译器不会去链接一个仅仅只包含categories的文件 ,就会导致你调用类别中的方法时,出现"selector not recognized",也就是找不到方法定义的错误。为了解决这个问题,引入了-Obj-C标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来。说到这呢你是不是认为-Obj-C就能搞定一切了呢?错!在64位的Mac系统或者iOS系统下,链接器有一个bug,会导致只包含有类别的静态库无法使用-ObjC标志来加载文件。变通方法是使用-all_load 或者-force_load标志,它们的作用都是加载静态库中所有文件,不过all_load作用于所有的库,而-force_load后面必须要指定具体的文件。这就是为什么我们经常会-ObjC和-all_load一起用了。
所以到这就有答案了,IQUIWindow+Hierarchy.m是一个使用类别来扩展已有类的文件,如果没有加-ObjC和-all_load就不会编译进去,作者为了确保不出问题,定义了一个宏,这个宏呢定义了一个假的类,这个假的类就会让链接器把这个文件编译进去。