iOS的静态库和动态库

一、静态库和动态库的区别

库:是资源文件和代码编译的一个集合

静态库: 静态库是在编译时,完整的拷贝至可执行文件中,被多次使用就有多次冗余拷贝;

动态库: 程序运行时由系统动态加载到内存,而不是复制,供程序调用。系统只加载一次,多个程序共用,节省内存。因此,编译内容更小,而且因为动态库是需要时才被引用,所以更快。

静态和动态的名字,区分了编译后的代码是以何种方式链接到目标程序中的。

二、静态库和动态库的形式

静态库:.a.framework

动态库: .dylib.framework

framework为什么可能是动态库,也可能是静态库?系统的.framework是动态库, 我们自己建立的.framework是静态库。

Bundle的概念,framework是一种特殊类型的Bundle,bunlde是一个包含多个子文件夹的文件夹。在iOS上,Bundlue将相关联的文件(比如图片, Nibs,代码)编译成一个包文件。程序将它当作一个单独文件来处理,你可以在不知道内部实现的情况下使用它。

而库需要一些其他资源:头文件,本地化文件,图片资源,文档和示例。我们可以将其打包成一个bunlde,这就是framework。

静态库包含静态资源包,动态库包含动态资源包,而且动态库可能包含同一个动态资源包的不同版本。

三、EMBEDDED, UNBRELLA, MODULAR

即使我们将资源文件(图片等)打包到frameworks里,Xcode仍然未能引用它们。通过embedding framework让我们可以访问这些资源文件,操作步骤见链接 add your framework in the "Embed Frameworks" section.

Umbrella frameworks的定义: Umbrella frameworks add minor refinements to the standard framework structure, such as the ability to encompass other frameworks

umberllar framework的目的是 隐藏不同frameworks之间的复杂依赖关系。它允许你将不同的frameworks合并成一个framework,输出部分头文件。为了构建一个umbrella framework,你必须包含umbrella header。

为了能够引入framework modular,我们必须引入 module map

framework module ModularFramework{
  module Modulel{
    header "File1.h"
  }
  module Module2{
    header "File2.h"
  }
}

随后,使用module

import ModularFramework.Module1
import ModularFramework.Module2

CocoaPods允许使用umbrella和modular frameworks。如果你引入了pods到你的项目里,在Target->YourApp->Build Settings找查找modulemapumbrella可以看到它们的设置。

四、CocoaPods相关

  1. Podfile

默认使用静态库,即 # use_frameworks!#是注释标示)
添加use_frameworks!表明Pod使用动态库, Pods/Products里都是动态库(.framework文件)
不添加use_frameworks!表明Pod使用静态库, Pods/Products里都是静态库(.a文件)

use_frameworks的效果

  1. 在使用静态库时,某些Pod不支持module怎么办?

可以使用use_modular_headers!来让所有Pod支持静态库;

或者对不支持静态库的Pod后面添加:modular_headers => true来使其支持module

五、#import和@import

可以先看个例子:

@import MapKit;
@import MapKit.MKAnnotation;
#import <MapKit/MKAnnotation.h>

@import是iOS7之后的新特性与法: Modules(模块导入)或者"语义引入"。Modules可以看成是可执行framework的集合,比#import更加快捷和高效。Enable Modules是默认打开的,在Target->YourApp->Build Setting->搜索Modules, 可以看到Enable Modules默认是YES,Link Frameworks Automatically也是默认打开的。打开后,使用原来的#import#include,编译器会在编译的时候自动把可能的地方换成modules的写法去编译。

@import的一个优势是开发者不需要手动将framework添加到project settings里面,它是自动完成的。

使用Modules的形式,可以使用@import MapKit;, 还可以只加载framework里的submodules,如@import MapKit.MKAnnotation;

六、常见问题

Q:可以在runtime时加载动态库吗?

A:不可以(除非你不想上AppStore)。苹果不允许在审核后更改app的行为,类似于热修复.

Q: 可以用Swift创建静态库吗?

A:在Xcode9后,可以。CocoaPods 1.5.0也支持Swift Static Framework.

Q:我可以使用多少动态库?有限制吗?

A:我们建议将动态库控制在一定范围内。虽然有可能创建很多的动态库,但是建议尽量不要创建太多的动态库,而使用静态库。

Q: Podfile使用静态库时出现报错[!] The following Swift pods cannot yet be integrated as static libraries:,如何解决?

A:pod install 时的错误信息提示我们应该使用use_modular_headers!来让整个项目支持静态库,或者对单个Pod使用:modular_headers => true

参考链接

推荐阅读更多精彩内容