一,所谓的“库”
* 所谓的“库” 库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。什么时候我们会用到库呢? 一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。 另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。 上面提到库在使用的时候需要 Link,Link 的方式有两种,静态和动态,于是便产生了静态库和动态库。 *库的分类 (1)开源库 公开源代码,能看到具体实现 比如SDWebImage、AFNetworking(2)闭源库
不公开源代码,是经过编译后的二进制文件,看不到具体实现 主要分为:静态库、动态库二,静态库和动态库 *静态库 静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a与framework)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。 静态库的好处很明显,编译完成之后,库文件实际上就没有作用了。目标程序没有外部依赖,直接就可以运行。当然其缺点也很明显,就是会使用目标程序的体积增大。 静态库链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝 *动态库动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib/.tbd)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。
动态库的优点是,不需要拷贝到目标程序中,不会影响目标程序的体积,而且同一份库可以被多个程序使用(因为这个原因,动态库也被称作共享库)。同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行(Linux 下喜闻乐见的 lib not found 错误)。 动态库链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存* Xcode中.framework和.a语言支持情况
库类型/语言类型 | OC | Swift |
---|---|---|
静态库 | iOS7+ | 不支持 |
动态库 | iOS8+ | iOS8+ |
使用Swift开发动态库的方式提供SDK,所以只能支持到iOS8+。但这意味着所有使用我的SDK的客户的APP都必须到iOS8+,这点需要斟酌一下。
所以假如需要支持iOS7的话,只有使用OC语言开发.a静态库的一条路。三,iOS Framework
除了上面提到的 .a 和 .dylib/.tbd 之外,Mac OS/iOS 平台还可以使用 Framework。Framework 实际上是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。
在 iOS 8 之前,iOS 平台不支持使用动态 Framework,开发者可以使用的 Framework 只有苹果自家的 UIKit.Framework,Foundation.Framework 等。这种限制可能是出于安全的考虑(见)。换一个角度讲,因为 iOS 应用都是运行在沙盒当中,不同的程序之间不能共享代码,同时动态下载代码又是被苹果明令禁止的,没办法发挥出动态库的优势,实际上动态库也就没有存在的必要了。
由于上面提到的限制,开发者想要在 iOS 平台共享代码,唯一的选择就是打包成静态库 .a 文件,同时附上头文件(例如)。但是这样的打包方式不够方便,使用时也比较麻烦,大家还是希望共享代码都能能像 Framework 一样,直接扔到工程里就可以用。于是人们想出了各种奇技淫巧去让 Xcode Build 出 iOS 可以使用的 Framework,具体做法参考和,这种方法产生的 Framework 还有 “伪”(Fake) Framework 和 “真”(Real) Framework 的区别。
iOS 8/Xcode 6 推出之后,iOS 平台添加了动态库的支持,同时 Xcode 6 也原生自带了 Framework 支持(动态和静态都可以),上面提到的的奇技淫巧也就没有必要了(新的做法参考)。为什么 iOS 8 要添加动态库的支持?唯一的理由大概就是 Extension 的出现。Extension(可拓展功能) 和 App 是两个分开的可执行文件,同时需要共享代码,这种情况下动态库的支持就是必不可少的了。但是这种动态 Framework 和系统的 UIKit.Framework 还是有很大区别。系统的 Framework 不需要拷贝到目标程序中,我们自己做出来的 Framework 哪怕是动态的,最后也还是要拷贝到 App 中(App 和 Extension 的 Bundle 是共享的),因此苹果又把这种 Framework 称为 。
四,Swift支持
跟着 iOS8 / Xcode 6 同时发布的还有 Swift。如果要在项目中使用外部的代码,可选的方式只有两种,一种是把代码拷贝到工程中,另一种是用动态 Framework。使用静态库是不支持的。 造成这个问题的原因主要是 Swift 的运行库没有被包含在 iOS 系统中,而是会打包进 App 中(这也是造成 Swift App 体积大的原因),静态库会导致最终的目标程序中包含重复的运行库(这是)。同时拷贝 Runtime 这种做法也会导致在纯 ObjC 的项目中使用 Swift 库出现问题。苹果声称等到 Swift 的 Runtime 稳定之后会被加入到系统当中,到时候这个限制就会被去除了(参考 的问题描述,也是来自苹果自家文档)。五,CocoaPods 的做法
在纯 ObjC 的项目中,CocoaPods 使用编译静态库 .a 方法将代码集成到项目中。在 Pods 项目中的每个 target 都对应这一个 Pod 的静态库。不过在编译过程中并不会真的产出 .a 文件。如果需要 .a 文件的话,可以参考,或者使用 这个插件。
当不想发布代码的时候,也可以使用 Framework 发布 Pod,CocoaPods 提供了vendored_framework
选项来使用第三方 Framework,具体的做法可以参考和。
对于 Swift 项目,CocoaPods 提供了动态 Framework 的支持,通过 use_frameworks!
选项控制。
更多有关代码分发的扩展资料可以参考这篇博客:
六,集成第三方库
原本SDK已经作为别人APP工程里的第三方了,假如SDK中需要引用AFNetworking类似的三方库。
库类型/引用 | 内部引用 | 外部引用 |
---|---|---|
静态库 | 静态库无法再包含其他的.a静态库。只能把源码放进去一起编译。 | 静态库无法把第三方放在外部,否则就不叫“静态”了。只能打包进SDK内部,并修改类名,防止外部冲突。 |
动态库 | 如果用Swift 可以直接引入源码,由于Swift 含有命名空间,所以不会有冲突。 | 第三方库不打进去,放在外部,比如cocoapods 的方式。别人编译的时候需要在他的环境里有该第三方依赖库。当提供给别人SDK的时候,你还需要给别人一个podfile。 |
七,补充
* 源程序
源程序,是指未经编译的,按照一定的程序设计语言规范书写的,人类可读的文本文件。通常由高级语言编写。源程序可以是以书籍或者磁带或者其他载体的形式出现,但最为常用的格式是文本文件,这种典型格式的目的是为了编译出计算机可执行的程序。将人类可读的程序代码文本翻译成为计算机可以执行的二进制指令,这种过程叫做编译,由各种编译器来完成。一般用高级语言编写的程序称为“源程序”。 * 目标程序 目标程序,又称为“目的程序”,为源程序经编译可直接被计算机运行的机器码集合,在计算机文件上以.obj作扩展名----由语言处理程序(汇编程序,编译程序,解释程序)将源程序处理(汇编,编译,解释)成与之等价的由机器码构成的,计算机能够直接运行的程序,该程序叫目标程序。目标代码尽管已经是机器指令,但是还不能运行,因为目标程序还没有解决函数调用问题,需要将各个目标程序与库函数连接,才能形成完整的可执行程序。 * *-
- 预处理:预处理相当于根据预处理命令组装成新的C程序,不过常以i为扩展名。
- 编译: 将得到的i文件翻译成汇编代码。s文件。
- 汇编: 将汇编文件翻译成机器指令,并打包成可重定位目标程序的O文件。该文件是二进制文件,字节编码是机器指令。
- 链接: 将引用的其他O文件并入到我们程序所在的o文件中,处理得到最终的可执行文件。