iOS开发笔记:-ObjC所引发的那一个大坑

加入-ObjC连接参数后项目走火入魔的事件由来以久,往日只曾据说,却从未见过。最近门派开发产品的时候,本人经身经历了一番。html

这个坑是怎么来的?

公司项目遇到的状况以下:首先咱们公司的项目是用CocoaPod构建的,CocoaPod在生成项目的时候会自动在Other Link Flags配置项上打上-ObjC,并且,即便强行去除-ObjC选项也没法解决,虽然编译可经过,可是运行的时候,友盟、MJRefresh等众多库均会报错没法运行。
同时,公司的项目基于另外一个分公司所提供的一个基础服务framework,这个framework具体实现未知,目前看来应该是使用c++开发,同时库必须禁用掉-ObjC选项,不然会报 duplicated symbols错误,编译都没法经过。
因而坑就这样出来了。c++

-ObjC是干吗的?

简单来讲,-ObjC连接指令是用来解决static library在运行时调用category方法报selector not recognized错误时使用的。也就是说,若是你在一个static library里面声明了一个category,在运行的时候调用这个方法就颇有可能会出现这个错误,而这个错误本不该该出现,由于你已经定义了那个方法。
那么,为何会出现这样一个问题?objective-c

为啥会出 method not recognized 错误

简单来讲,这是由于UNIX 的静态库(.a文件)与OC的动态机制之间的不协调致使的。
咱们先来看通常状况下,UNIX静态库及C程序的一个连接过程。当一个C语言程序编译的时候,全部的源代码会被编译为对象文件,即.o文件(object file)。这些对象文件中包含了相应的可执行程序,以及相应的静态数据。连接器最终须要将全部这些对象文件组合到一块儿从而产生一个最终的可执行文件。
当一个源文件引用了定义于其余文件中的一些东西的时候(好比引用其余文件的一个方法),一个 undefined symbol就被写入了它所产生的object 文件,而后等待最终被解释掉。在最终构建可执行文件的时候,连接器将从包含这些undefined symbols的object文件中拉取信息以解决掉以前被标记的undefined symbols。
一个UNIX的静态库其实就是一系统object file的集合,然而,通常状况下只会拉取那些,他须要的object file。而这样作的好处是能够减少最终可执行文件的大小。app

举个例子

好比main.c使用一个函数,名叫foo( ),而这个函数定义于B.c里面。在生成.o文件的时候,main.o就会有一个foo( ) 的undefined symbols标记。在连接期间,B.o文件便会被打入最终的可执行文件中。可是,假如另外还有一个C.c,里面定义了的函数并没被使用到,那么最终,这个C.o文件便不会出如今最终的可执行文件中。函数

Objective-C有什么不一样?

然而众所周之,oc是具备必定动态性的语言,只有在最终运行的时候,对象方法的具体实现只有到被调用的时候才会被肯定。基于这个缘由,Objective-C并无对方法级别定义符号,而是只对类级别定义符号。
举个栗子。好比在main.c中包含如下代码: [[FooClass alloc] initWithBar:nil]; 那么在连接的时候,main.o在生成的时候就会包含一个未定义符号(Undefined Symbols) FooClass,但却不会定义符号 initWithBar。code

因此为何会产生这个坑?

坑爹的是,Category只是一个方法的集合,而对一个Cateogry中的方法的调用,并不会生成未定义符号,这就意味着连接器并不知道要去加载这个Cateogry文件所生成的object 文件。因而,在最后运行的时候,运行时系统便会没法找到相应方法的定义,从而抛出unrecognized selector 错误。htm

-ObjC干了啥?

那为啥加上-ObjC就行了? 原来,加上-ObjC选项的时候,连接器便会加载静态Library里面全部Objective-C实现的类和Cateogry。对象

还有啥选项?

除了-ObjC,文档上还有几个其余的选项,也值得咱们关注一下。事件

  • -all_load 全加载,意思是加载全部静态库的成员。不管是c仍是c++还oc。开发

  • -force_load path_to_load 对某个指定静态库全加载。而-all_load则会对全部的库进行全加载。

这到这里,这个问题貌似已经能够解决了。嗯,分公司的开发确定在framework里面打包了几个没有用到的额外同名实现,而加上-ObjC,会将全部方法全加载上,因而duplicated symbols错误便被抛出。
那么,若是libPod,也就是pod库生成的静态库前面加上-force_load,而不加上-ObjC,问题不就顺利解决了?

参考文章: <<Apple Technical Q&A QA1490 >>
<<Objective-C categories in static library>>
<<Linker error using CocoaPods>>

相关文章
相关标签/搜索