静态库和动态库的制作(OC、Swift)

什么是库?

库是程序代码的集合,是共享程序代码的一种方式。我们根据源代码的公开情况,可以将库分为 2 种类型

  1. 开源库:公开源代码,我们能看到代码的具体实现,比如 SDWebImageAFNetworking等;如何将自己的代码发布到代码托管平台中,然后借助CocoaPods 供别人使用,我们在上一篇文章中已经讲过,这里不再细说。
  2. 闭源库:不公开源代码,是经过编译后的二进制文件,看不到代码的具体实现。闭源库主要分为:静态库、动态库

静态库和动态库的存在形式以及使用上的区别

存在形式:
静态库:.a 和 .framework
动态库:.dylib 和 .framework

区别:
静态库:链接时,静态库会被完整地复制到可执行文件中, 被多次使用就有多份冗余拷贝 ,如下图:


静态库

动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,以节省内存,具体形式如下图所示:


动态库

静态库的使用场景:

  1. 项目开发中我们经常使用到的极光推送、百度地图、友盟分享等等。这些大公司都有自己的核心业务,同时又希望我们去使用他们提供的技术,但是又不想暴露他们的代码,因此他们采用"闭源"的方式来让我们集成。
  2. 将MRC的项目放到ARC环境下,我们可以如下图去操作

    MRC->ARC

    但是如果文件特别多,我们这样一个个去操作是不是很麻烦?其实我们可以将MRC的项目,打包成静态库, 可以在ARC下直接使用, 不需要转换,非常方便;

知识准备:
我们都知道模拟器下的静态库和真机下的静态库是不能混用的,那为什么呢?其实主要原因是模拟器和真机的CPU架构不一样(各个模拟器型号之间架构也不一样)不同机型的CPU, 对应的架构不同;
模拟器:

  1. 4s和5使用的是i386
  2. 5s-6sPlus使用的是x86_64

真机:

  1. 3gs---4s : armv7
  2. 5/5c : armv7s(armv7兼容armv7s)
  3. 5s---6sPlus:arm64

我们可以分别选中不同的模拟器, 进行编译,然后利用lipo -info xxx.a 查看静态库所支持的架构, 如下图所示:


查看静态库支持架构

因为CPU架构的不同,这就造成了一个问题,如果我是在6s环境下编译生成的静态库运行到5上面就会编译不通过, 怎样可以一次编译支持多个架构的的静态库呢?
可以通过Build Settings -> Build Active -> NO,表示不止编译活跃的架构, 让所有的架构都编译,如下图所示:


编译所有架构

.a静态库的制作步骤

  1. 新建项目-> 选择 “Cocoa Touch Static Library”


    新建静态库
  2. 添加库需要包含的源代码,并且设置需要暴露的头文件:


    3.png


    引入制作的静态库所需要的网络框架(有些会自动引入,有些需要手动引入,根据编译报错,可以检查。)


    引入框架
  3. 设置支持所有架构:


    设置支持架构
  4. 编译前检查一下是debug模式还是release模式,选择release模式。在模拟器和真机中分别编译后,libzpstaticLibrary.a就由红色变成了黑色,Show in Finder在目录中查看:


    Release模式

.framework静态库的制作步骤

  1. 新建项目-> 选择 “Cocoa Touch Framework”

    Framework
  2. 添加库需要包含的源代码,并且设置需要暴露的头文件:


    暴露头文件


    如果用户需要导入的头文件过多怎么办?我们可以使用一个主头文件包含其他头文件, 让用户只导入一个主头文件。

  3. 编译时, 设置编译所有架构


    设置编译架构
  4. 因为默认制作的是动态库,我们 需要设置链接类型target -> Build Settings-> 搜索 Mach-o Type ;改为静态库


    设置类型


    如果没有这一步,我们在测试的时候会报一个错误:


    错误提示


    这个错误是因为我们默认生成的是一个动态库,如果我们把它当成一个动态库来用的话 就需要在测试工程中General->Embedded Binaries中导入我们这个动态库,这样就不会报这个错误了。


    动态库

经过以上步骤后我们就可以成功的生成了一个.Framework的静态库或者是动态库了。

静态库的操作

合并静态库

因为静态库针对于模拟器和真机生成了不同版本(支持不同架构), 所以没法同时运行,但是我们可以将二者进行合并,合并后的.a大小大约是不合并的2倍左右。
cd 到一个目录,然后通过

lipo -create Debug-iphoneos/libTools.a   Debug-iphonesimulator/libTools.a  -output  libTools.a

进行合并,合并后的架构如下图所示:


分解合并库

既然有合并静态库,那么对应的也有分解合并库,例如我们在发布的时候只想要使用arm64架构,那么我们可以通过下面这行命令来达到我们目的:

lipo -thin arm64 静态库 -output 新的静态库名称

如下图所示:


查看分解之后的库可以发现该库已经非常小了

从合成库中移除某个架构

如果合成库中的某一个架构我们用不到了,想要移除,那么我们可以通过下面的命令,例如我们想要将合成库中的i386移除

lipo -remove i386 静态库 -output 静态库名称

执行命令后我们可以发现,合成的静态库中已经没有了i386这个架构了


总结

.a静态库和.framework静态库的区别?

我们都知道静态库包括.a.framework,那么二者之间到底有什么区别呢?

  1. .a是一个纯二进制文件, 而.framework中除了有二进制文件之外还有资源文件,比如Bunle、Plist等。
  2. .a文件不能直接使用, 至少要有.h文件的配合; .framework文件可以直接使用
  3. .a + .h + sourceFile = .framework
  4. 建议使用.framework

静态库的调试

因为静态库只提供了一些头文件,实现代码都是经过二进制化的,如果我们想对静态库进行断点调试如何做呢?
我们可以创建复合项目来对静态库进行调试:

  1. 创建一个测试工程,选中TARGETS,点击下面的➕按钮,添加一个静态库,如下图所示

    复合项目
  2. 设置主工程文件和静态库的依赖关系。

    添加依赖关系

经过以上两步后我们就可以对要制作的静态库文件进行调试开发了,是不是很爽,至于制作静态库就和上面的步骤一样了。

Swift打包动态库

  1. 因为Swift项目是不支持静态库的,必须使用动态库。所以我们在新建一个静态库的时候,一定要选择Cocoa Touch Framework

    创建动态库

    如果我们在项目中将target -> Build Settings-> 搜索 Mach-o Type ; 改为Static Library

    静态库

    Command+B编译,系统会报一个错,提示我们Swift is not supported for static libraries.如下图:

    静态库报错

    所以,如果在Swift项目中,我们必须使用动态库;
  2. 因为Swift是没有头文件这个说法的,所以在Build Phases中我们也不用设置暴露头文件了

    11.png
  3. 确定支持模拟器或者真机中的所有架构

    编译架构
  4. 最重要的,因为swift没有头文件,所以如果我们想让别人用到我们的方法,就用Public修饰符修饰。

    暴露方法

    这样生成的动态库中就会将我们的Swift方法转换成了OC的方法
SWIFT_CLASS("_TtC10zpSwiftLib4Tool")
@interface Tool : NSObject
+ (void)Log;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

这样将生成的动态库拖入到我们的测试工程中就可以成功的使用了,但是和静态库有一点不同的是,我们需要在测试工程中General->Embedded Binaries中导入我们这个动态库即可。



作者:Mark_Guan
链接:http://www.jianshu.com/p/f14553494d88
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(静态库和动态库的制作(OC、Swift))