目录:
1. 库是什么?
2. 静态库与动态库的区别
3. 使用库
4. iOS系统中的库
库是什么? 下面这张图大家一定很熟悉,这是windows上经常见到的一幕,我们可能刚刚安装完一个软件或者某个大型游戏,满心欢喜的准备启动时,蹦出这个东西:
文章图片
这个就是库引起问题,具体我们下面会进行分析。那么库是什么?
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。通俗地讲,库就是一个组件,一般是可以复用的组件,这样每个需要这个组件的程序都可以使用这个组件,如果组件的代码内联在程序中,则失去组件的意义。
开发中为了实现快速迭代,我们通常要避免造轮子:首先自己造的轮子问题多,其次造轮子时间长。 所以我们通常会考虑开源库。
开源库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。使用开源库首先必须了解代码所遵循的协议,常见的协议如gpl bsd mit等,分清各种协议需要承担的责任,例如我们使用的这份代码的头文件中描述了协议:
文章图片
其他开源库都相应github页面上都会描述遵循的协议。
大家如果留意iOS系统中可以享用的开源库,会发现作为一个iOS开发者的幸福:大量有用高质量的开源库,并且使用相对宽松的多的协议,可以让开发者使用的同时不用太关注侵权和付费问题,而大家如果使用大型的开源库时,比如音视频处理的ffmpeg,会发现这个库使用了严苛的协议,开发者使用时就要关注是否修改源码?修改后如果负责?使用了如何收费?是否侵权等诸多问题。
我想这也是iOS开发者为何这样如泉涌一般出现,因为这样一个开放、相对自由又低门槛的环境让许多新人有一个更快进入、更熟练进阶的学习曲线。
协议参考:
http://blog.csdn.net/nightmare/article/details/12405109
http://www.cnblogs.com/Wayou/p/how_to_choose_a_license.html
静态库与动态库的区别
库按照链接的方式可以分为两种,静态库和动态库。
静态库 【静态库】是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。静态库的代码在编译链接后已经被载入可执行程序,因此体积较大。静态库的“静态”是指编译链接后库已经固定在可执行文件中,如果需要更新库中内容,需要重新编译链接,才能在可执行程序中生效,对程序的更新、部署和发布页会带来麻烦。
静态库可以看成是一堆对象.o文件(object files)的归档,所以静态库可以通过ar -x xxxx.a 来分解出其中的所有.o文件。当链接这样一个库到应用中时,static linker将会从库中收集这些对象.o文件并把它们和应用的对象代码一起打包到一个二进制文件中。这意味着应用的可执行文件大小将会随着库的数目增加而增长。另外,当应用启动时,应用的代码(包含库的代码)将会一次性地导入到程序的地址空间中去。
参考下图:
文章图片
app加载静态库 动态库 【动态库】在程序编译时并不会被链接到目标代码中,如下图可见,可执行文件中只是保存动态库各个api的引用,保留着相对地址,在程序运行时,等可执行程序中使用动态库的某个api时,动态库会载入到内存某个区域(非当前可执行文件所在内存块),可执行程序所在进程将会生成这个动态库的空间映射,从而被进程调用。
由此可见,动态库是直到程序启动时被需要时才加载到内存(增加了启动时间,如果需要运行时再加载,需要处理),app启动时,系统在内核态完成一些必要配置,从App的MachO文件解析出dyld的地址启动dyld,然后通过dyld加载依赖的动态库。 并且,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题(目前在iOS系统上不会这样,因为iOS系统的沙盒机制禁用了进程之间的动态库共享)。动态库在程序启动时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,可以实现增量更新。
文章图片
app加载动态库
iOS中的dylib支持上述形式,但其他动态库不支持。
windows系统支持上图形式:dll动态库,
自己开发的程序可以加载系统的dll,这样程序的大小变得很小。对于开篇windows上碰到的弹窗问题,其实问题就在动态库的致命弱点上:由于一个系统中的不同软件如果是基于同于dll的不同版本,不同版本dll之间的接口或内部逻辑又有所差异就会造成系统中某个软件可以用,其他就不可以用,但同一时刻系统又只保留一个dll,所以无法保证这些软件都能正常使用。
这也体现了windows和iOS两个系统对动态库的宽容性,前者对每个系统版本中dll的兼容性做的不好,并且允许用户自己生成的dll文件,而后者兼容做的好的多,apple这方面为了避免出现这个情况,在iOS8之前是不允许用户自定义的动态库出现的,提交到appstore的应用不能包含动态库,但是iOS8之后apple开放了这个限制,用户可以在app中使用动态库。 但是apple 审核中注明了,不允许动态下发代码,所以通过更换app中的动态库实现增量更新是行不通的(每个app提交后都是经过签名的,如果app使用了动态库,也会同时签名,在app校验签名通过才能运行,如果直接替换动态库,签名这关过不了。对于不发布到appstore的应用可以参考这里通过framework动态更新)。我们常用的第三方库管理工具carthage打包的framework就是动态库。
mac中区分两种库
那么我们平时如何知道使用的库是动态库还是静态库呢?最简单的方式就是mac电脑上的finder可以识别两种库,如下图:
文章图片
动态库
文章图片
静态库 从上图可以看出,动态库在finder中的预览图跟其他可执行文件一样是exec形式,而静态库没有对应预览图。
这里还有个问题,上面我们已经分析到,动态库中不会直接将外部引用链接进去,所以对于较大的工程一般静态库都比动态库小很多,但是上图例子中我没有添加任何源码的情况下,空的动态库比静态库大不少,用sublime打开发现动态库中很大部分都是00, 这是怎么回事有待求证。
使用库 上面提到了动态库比静态库好的方面,那么我们在项目中应该怎么取舍?直接用动态库吗?
这里需要注意,动态库虽然文件小,占据空间小,但是我们在app中使用时由于与可执行文件是独立放在ipa中,因为在运行时在加载到内存中,所以xcode工程配置(如下图)需要将二进制文件嵌入进去,这样实际上我们生成的app的大小比使用静态库会大。
文章图片
xcode配置使用动态库
如果是静态库,这步可以省略。
所以实际项目中可以根据需求判断,是想要运行时启动时加载库少,占用内存少,启动快? 还是app安装文件小(过大会被appstore限制,后期可能影响其他需求的添加)?
【iOS中的库】我们一般何时需要使用第三方库:
- 需要轮子
开发中,有一个重要原则:D R Y 对应着 don‘t repeat yourself
也就是说我们要避免重复的代码,不仅是自己重复的代码要做好重构和复用,也避免写一些别人已经写好的代码,用好第三方库。 - 协同开发
以一个大型工程为例:
如果一个大型工程可能包含消息 空间 voip电话 公众号 圈子 等很多功能模块时,这些模块都属于不同小团队负责,这个大工程需要加载所有这些模块,需要编译迅速,主线版本稳定,通常都要各个模块需要独立工程管理,主工程通过加载各个子工程的静态库来编译运行,这样每个小模块的开发人员只需要关注自己模块内部的工程,编译速度快,整个团队的效率高。 - 共享代码或者以库为产品
就像我们使用他人的源码或库一样,我们也可以把自己积累的比较通用的源码分享出去,让其他人集成来提高开发进度,或者将我们的源码编译成库,商业运作形式变卖。这时我们就需要确定自己的协议,也就是说别说使用我们的源码或库需要履行哪些责任,怎么付费等