细说iOS静态库和动态库

细说iOS静态库和动态库

对于讲解iOS中静态库和动态库的文章已经不少了,以前本身也总结了一篇。从今天目前来讲,以前就是总结了皮毛。今天的文章也算是后续的总结,应该随着后面的深刻还会有不一样的体会。ios

iOS中的静态库和动态库

静态库

  • 静态库彻底复制进可执行的二进制里面
  • 后缀是.a或者.framework

动态库

  • 动态库是在程序冷启动时候被连接到手机内存或者 App 内存里面
  • 后缀是.tbd或者.framework

关于说明不少,能够看一下网上的文章。我如今说的是基于上面理论的证实。刚开始以为网上说的可能不太准确,后来获得验证是正确的。git

为了研究咱们建立的.a.framework究竟是静态库和动态库,咱们分别建立对应的简单的库。github

咱们分别能够经过上面图中红色区域建立.framework.a。咱们知道区分是静态库仍是动态库最终是咱们选择的 Mach-O 的类型究竟是Dynamic Library仍是Static Libraryxcode

Mach-O 类型

这里简单说一下Mach-O类型,为何说简单说一下。由于深刻我也不了解了,深刻能够谷歌资料。bash

  • Executable:应用的主要二进制架构

  • Dylib Library:动态连接库(又称DSO或DLL)mvc

  • Static Library:静态连接库框架

  • Bundle:不能被连接的Dylib,只能在运行时使用dlopen( )加载,可当作macOS的插件iphone

  • Relocatable Object File:可重定向文件类型post

上面的解释也是抄别人的(小声).

静态库和动态库的对比

为了让打出来的库更加的真实,咱们使用网上出名的库做为测试。咱们选取的是FLEX做为测试的目标,由于这个库所包含的文件多,数据真实性更加的可靠。咱们编译的环境是基于iPhone 6s Plus进行编译出来的,真正的大小会包含其余框架会比我测试大得多。

二进制大小

二进制大小(iPhone 6s Plus) .a .framework
静态库 6.8MB 4.6MB
动态库 1.6MB 1.6MB

为了验证咱们所谓静态库和动态库是不是真正的静态库和动态库,咱们使用File命令和Mach-O查看软件分别对比一下。

File 命令

输出显示 .a .framework
静态库 ✅(current ar archive) ✅(current ar archive)
动态库 ✅(Mach-O 64-bit dynamically linked shared library x86_64) ✅(Mach-O 64-bit dynamically linked shared library x86_64)

Mach-O 查看

输出显示 .a .framework
静态库 ✅(Static Library) ✅(Static Library)
动态库 ✅(Shared Library) ✅(Shared Library)

咱们对比结果发现,不论是.a仍是.framework均可以做为动态连接库来使用,这和咱们在网上看到文章说.a是静态库是不严谨的。

咱们按照静态库是完整被拷贝到工程二进制里面,动态库是在启动时候动态连接的描述,咱们分别对比一下运行包里面的表现。咱们一样是按照iPhone 11 Pro Max作为对比的,这样数据比较真实。

静态库和动态库在包里面的表现

Static Library.a.framework

代码所在的位置
代码所在位置(iPhone 6s Plus) .a .framework
静态库 App 二进制中 App 二进制和 Frameworks 文件夹中
动态库 无(二进制没有 Frameworks文件夹 没有) Frameworks 文件夹中
App 二进制大小对比
App二进制大小(iPhone 6s Plus) .a .framework
静态库 93KB 93KB
动态库 92KB 92KB
启动速度对比
冷启动
冷启动速度(iPhone 6s Plus) .a .framework
静态库 151.44毫秒 53.35毫秒
动态库 0 毫秒(运行报错) 254.58毫秒
热启动
热启动速度 .a .framework
静态库 160.99 毫秒 154.65 毫秒
动态库 0 毫秒(运行报错) 199.04 毫秒

这里描述的冷启动是指代程序第一次安装以后运行可能会加载系统动态库而形成启动时间边长,热启动是第二次启动不须要加载系统动态库。

经过上面的代码位置,二进制大小,冷启动速度和热启动速度大概能够得出一个结论。虽然严格来讲.a是支持打包出来动态库的,可是代码不会复制进二进制,也不会存放在Frameworks里面。形成咱们打出来的动态库.a在程序里面没法运行,也就换句话说.a只支持静态库特征了。

虽然.a的静态库的热启动比冷启动还要慢,可是这几毫秒的偏差能够抛弃。可能基于咱们手机已经打开了其余应用形成冷启动没有再次加载系统动态库而和热启动速度差很少。

可是对比.framework能够得知静态库的启动速度确实比动态库的加载速度快不少。而静态库的.framework会存在两份,因此安装包会变大,由于静态库的.framework直接复制进二进制里面,因此二进制会变大。

经过上面咱们得出下面的结论

  • .a只支持静态库(打包出动态库也是支持的 只不过目前 iOS 不支持加载)
  • .framework静态库会存在于二进制和Frameworks两份。
  • 热启动会比冷启动快的多
  • 静态库比动态库加载快得多
  • 静态库.framework.a的二进制文件小的多
  • 静态库和动态库都推荐用.framework不推荐用.a

XCFrameworks

XCFrameworks 和以前 Framework 对比

说完了咱们经常使用的动态库和静态库,咱们说一下今年出的新特征XCFramework。根据以前一篇文章了解,XCFramework是为了取代以前的.framework的。

我很想深刻的探究一下XCframeworks来谈一下用这个的好处,可是苹果对于这个的资料少之又少。咱们经过真实的对比一下XCFrameworks的好处。

咱们经过对比包含模拟器真机.framework和对比.xcframework对比一下数据。

对于生成多架构的.framework咱们须要用到lipo命令进行合成,可是对于生成.xcframework能够用到个人xcbuild的脚本生成。

(X86_64 + ARM64) .framework .xcframework
文件大小 10.6MB 10.8MB
二进制大小 10.4MB 8.3MB+2.2MB
App 大小(iPhone 6S Plus Debug) 4.8MB 2.8MB
冷启动 169.8 毫秒 155.52毫秒
热启动 159.56 毫秒 153.62 毫秒

经过对比.xcframework.framework不但 App 大小少了不少,并且还对于启动速度提高了很多。

咱们以前说的能够将.a和头文件打包到.xcframework中,咱们下面尝试一下。

融合.a 和头文件

咱们事先准备好模拟器和真机架构的.a和头文件,使用下面的命令建立一个XCFrameworks.

xcodebuild -create-xcframework -library <path> [-headers <path>] [-library <path> [-headers <path>]...] -output <path>

//Example 
xcodebuild -create-xcframework -library /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphonesimulator/libMyLibrary.a -headers /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphonesimulator/include/MyLibrary -library /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphoneos/libMyLibrary.a -headers /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphoneos/include/MyLibrary -output /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/MyLibrary.xcframework
复制代码

包含第多个不一样的Framework(不支持)

假设咱们的MyFramework依赖一个咱们本身的另外的库或者其余第三方的库

xcodebuild -create-xcframework -framework <path> [-framework <path>...] -output <path>

//Example
xcodebuild -create-xcframework -framework /Users/zhangxing/Downloads/data/MyFrameworkB.xcframework/ios-arm64/MyFrameworkB.framework -framework /Users/zhangxing/Downloads/data/MyFrameworkB.xcframework/ios-x86_64-simulator/MyFrameworkB.framework -framework /Users/zhangxing/Downloads/data/ios-arm64/MyFramework.framework -framework /Users/zhangxing/Downloads/data/ios-x86_64-simulator/MyFramework.framework -output /Users/zhangxing/Downloads/data/MyFrameworkC.xcframework
复制代码

结果是一个 XCFrameworks只能包含一个框架,可是能够包含多个架构。和以前写的文章写的理解有误,这里纠正一下。

怎么将以前已经Fat Framework变成最新的XCFramework

若是有源码能够直接使用xcbuild命令生成,若是没有或者是其余第三方的可使用下面的命令。

lipo 静态库源文件路径 -thin CPU架构名称 -output 拆分后文件存放路径
复制代码

用分离出来的架构从新合成XCFrmaework

其实这样很麻烦,以后我会有空完善一下xcbuild的功能。写到这里这篇文章就写完了,对于静态库和动态库知道了一些,还有一些疑惑。对于XCFrmaework验证了一些猜测,也存在太多的疑问。

掘金年度征文 | 2019 与个人技术之路 征文活动正在进行中......

相关文章
相关标签/搜索