走近静态库(概述)

0x00 What?

库是共享代码的方式,通俗的讲就是把一个或者多个功能的实现相关代码打包成一个可供其它人直接使用的package.从本质上来讲库是一种可执行代码片段的二进制格式,可以被加载到内存中直接使用.

iOS中的库分为静态库和动态库.

  • 静态库有.a(库的api头文件和.a可执行文件组成)和.framework(其实就是把可执行文件和.头文件都包含在里一个*.framework文件夹里)两种形式,实际应用中大多数第三库都以.a的形式提供.
  • 动态库有.dylib和.framework形式,后来苹果又使用.tbd形式取代了.dylib.

1.0 静态库与动态库的区别

库的加载时机: 在pre-main阶段,动态为由动态库加载器来加载到内存中

1
2
3
4
5
6
7
8
Total pre-main time: 156.41 milliseconds (100.0%)
dylib loading time: 45.14 milliseconds (28.8%)
rebase/binding time: 27.77 milliseconds (17.7%)
ObjC setup time: 53.95 milliseconds (34.4%)
initializer time: 29.42 milliseconds (18.8%)
slowest intializers :
libSystem.dylib : 2.79 milliseconds (1.7%)
xxx.dylib : 16.05 milliseconds (10.2%)

静态库:

  • 程序链接时会完整的拷贝到可执行文件中,多个程序多次使用会在内存中有多份

动态库:

  • 程序链接时不会拷贝到可执行文件中,只有当程序运行时,系统会动态的加载到内在中,供程序调用,系统只会加载一次,如果其它程序也用到,则会在缓存中找,如果没有找到再加载到内存中,内存中只有一份.(苹果不允许开发者使用动态库)

1.1 .a与.framework的区别

.a = [xxx.h,….] + xxx.a + Option(xxx.bundle)

.a在工程中的引用方式为 #import "PublicHeader.h"

.framework = xxx.framework{Headers + 可执行文件,和.a一样只不过没有后缀 + modulemap} + Option(xxx.bundle), 其中module.modulemap这个文件的作用就是就是为framework生成一个规范的树状结构,具体更多细节请参考: Umbrella Header在framework中的应用

.framework在工程中的引用方式 #import <FuckingFramework/PublicHeader.h>

0x01 Why?

  • 闭源: 隐藏源码实现,比如要对外开放SDK
  • 节省编译时间: 由于静态库是已经编译好的可执行文件,在工程中使用时相对直接添加源码,省去了编译时间
  • 方便使用共享

0x02 How to make a library?

这里就不展开写了,网上一搜一大堆

2.1 Some principles for making library

  • 完善的文档: 可以方便别人快速参阅的使用,最好再能提供一个demo
  • 整洁的代码: 包括优雅的代码风格,漂亮的命名规范,精简的API接口,遵循接口隔离原则,开闭原则,良好的代码组织方式,详细的注释(除非你能做到代码自注释),最好是0 Warning,这毕竟是你的库的门面
  • 多CPU架构支持: 这能给一些开发者减少不少麻烦
  • 详尽的测试: 尽可能多的为你的每个API编写单元测试,这不仅能保证你的库的质量,也会给后面修改维护创建舒服的环境.
  • 尽可能不要使用第三方库: 因为有可能你使用第三方库并将它库编译到你的库中,使用者的工程中也使用了这个库,造成冲突.如果要使用最好将第三方库中的类名和前缀都改一下,还有一些全局变量.

2.2 Some Tips

  1. 发布编译库工程的时候,将schem调整为Release模式

  2. 当你看到如下警告时,设置工程的Build Setting里Enable Clang Module Debuging ->NO

    1
    2
    3
    4
    5
    6
    7
    note: Linking a static library that was built with -gmodules,
    but the module cache was not found.
    Redistributable static libraries should never be built with module debugging enabled.
    The debug experience will be degraded due to incomplete debug information.
    warning: /var/folders/nm/y29gjrfd64b8b8y0cgx5hhbc0000gn/C/org.llvm.clang.xxxxxx/ModuleCache/2VU6G8UDA25RM/CoreFoundation-271U74KHGUIO4.pcm: No such file or directory
    ...
    ...