iOS - 动态库与静态库

3,475 阅读3分钟

静态库 (Static Library)

  • 分发文件大

  • 静态库默认仅讲有用到的类文件linkMach-O中(已类文件为最小链接单位)

  • ipa包小(为了APP瘦身,尽量将代码放静态库中)

    • 静态库中某个目标文件的代码没有被任何地方引用,则这个目标文件不会被链接到可执行文件中去(前提是不要使用-Objc-all_load选项,分类代码经常被优化掉,一般都使用-force_load来处理静态库分类加载问题)
  • APP冷启动速度快

    • 前提是不使用动态库拆分搭配动态库懒加载方案
    • APP启动流程中有rebasebind,多个静态库只需要rebasebind一次
  • 存在符号冲突可能

  • 共享TEXT段

    • iOS9以前单个Mach-O的TEXT限制60M
    • iOS9以后单个Mach-O的TEXT限制500M
  • 不需要额外签名验证

  • 静态库符号的可见性可以在链接期间被修改

  • 文件格式多为fat格式的静态库文件

  • 形式多为.a.framework

  • 静态库不含bitcode时,引用静态库的目标部署时就不能包含bitcode

动态库 (Dynamic Library)

  • 分发文件小
  • ipa包大
    • 动态库会把整个lib复制进ipa
  • APP冷启动速度慢
    • APP启动流程中有rebasebind,多个动态库只需要多次rebasebind
  • 需要设置合适的runpath
  • 需要动态加载
  • 需要签名且需要验证签名
    • 会检查framework的签名,签名中必须包含TeamIdentifier,并且framework和host APP的TeamIdentifier必须一致
    • Xcode重签命,保证动态库签名一致性
  • 需要导出符号
  • 重复的arch结构
  • APP与动态库中重复代码可以共存,不会发生符号冲突
    • 因为可执行文件在构建链接阶段,遇到静态库则吸附进来,遇到动态库则打个标记,彼此保持独立性
    • 对于来自动态库的符号,编译器会打个标记,交给dyld去加载和链接符号,也就是把链接的过程推迟到了运行时执行。(比如APP使用的是3.0版本SDK,动态库使用的是1.0版本SDK,能正常运行,但是会有风险)
  • 连接后需要包含分发大小
  • 冷启动过程中,默认会在main函数之前加载
    • 默认情况下,过多的动态库会拖慢冷启动速度,可以使用dlopenbundle懒加载优化

  • 文件格式Mach-O(一个没有main函数的可执行文件)
  • 动态库不包含bitcode时,引用动态库的目标部署时可以包含bitcode
  • CocoaPodsv0.36.0开始,可添加关键字use_frameworks!编译成类似Embedded Framework的结构(可以称之为umbrella framework
    • 缺点:默认把项目的依赖全部改为动态库(可是使用use_modular_headers!,也可以在podsepc添加s.static_framework = true规避)
    • CocoaPods执行脚本把动态库嵌入到.appFramework目录下(相当于在Embedded Binaries加入动态库)