什么是库?
库就是把一对.h .m 图片资源 bundle 文件打包起来的一个文件。
库的分类
开源库:源代码是公开的,主要体现在可以看到.m 文件的内部实现。例如在 github 上大多数库下载下来之后,都可以看到 .h 和 .m 文件。
闭源库:不公开源代码,一般只暴露 .h 文件。一般都是编译过的二进制代码,看不到具体实现。
闭源库又分:静态库 & 动态库
静态库的存在形式:
.a
.framework
动态库的存在形式
.dylib
.framework
静态库和动态库的区别?
1. .a 一定是是静态库,dylib(dynamic library)一定是动态库。.framework 可能是静态库,也有可能是动态库。
2. 静态库在链接时,会被完全赋值到可执行文件中。如果多个 App 都使用了同一个静态库,那么每个 App 都会拷贝一份静态库,缺点是浪费内存。类似定义一个变量,使用该基本变量的时候,都是复制了一份便变量的值。
3. 动态库不会复制,只有一份,程序运行时动态加载到内存中,系统最多只加载一次,多个程序公用一份,节约了内存。类似于使用对象的引用。但是如果在 iOS 项目中使用了自定义动态库,苹果是不允许上架的。在 iOS 8 之后,苹果开放了动态加载 .dylib 的接口,用于挂载 .dylib 动态库。
使用静态库时,会被完全复制到可执行文件中,多次使用就多次复制。
动态库链接时不复制,程序运行时由系统动态加载到内存,供程序使用。
而且系统只会加载一次,多个程序公用,节省内存。
静态库的运用场景?
1. 保护公司的核心代码,如讯飞语音搜索摸索了好多年得到的成果当然要保存起来,都公开了,公司如何生存?
2. 将 MRC 的项目打包成静态库,可以在 ARC 模式下直接使用。免去了配置 .m 文件的 -fno-objc-arc
的配置。
静态库的运用场景?
.a + .h
.h 可以看到头文件,也就是方法的声明
.a & .framework 可以看作是所有的 .m 代码加密后的一个二进制文件。
.bundle
在使用第三方库的时候,有时候会带上 .bundle 文件。.bundle 实际上是一个物理文件夹,里面可以放图片等资源。
因为 .bundle 是一个物理路径文件夹,所以,里面放的资源文件不会和当前的 target 项目的资源文件重名。
.a 和 .framework
既然 .a 和 .framework 都可以完成静态库的封装。
它们之后有和区别呢?
使用 .a 打包静态库时,包含了 .a 静态库 + .h 头文件 + bundle 资源文件
使用 .framework 打包静态库时,所有的文件都包含在 .framework 包里了,比 .a 方便不少。
所有的库不管是.a .dylib .framework 最终目的,都是为了打包一堆
.h
,.m
,bundle
资源文件。并对外隐藏.m
的实现细节。
.a 静态库的制作步骤
第一步,创建一个 静态库项目
创建好的资源管理器
第二步,添加自己的 .h
, .m
文件,并实现。
由于系统会默认帮助我们添加一对
.h
.m
,所以我就不添加了。直接用这对。
第三步,在 .h
, .m
中定义方法的声明 和 实现。
+ (void)classMethod;
- (void)instanceMethod;
+ (void)classMethod {
NSLog(@"我是来自 RelaxALib.a 静态库的类方法");
}
- (void)instanceMethod {
NSLog(@"我是来自 RelaxALib.a 静态库的实例方法");
}
第四步骤,设置编译参数。
第五步,选择模拟器 AND 真机设备,分别 command + b 一次。完成 .a 库的编译。
第六步,右键 RelaxALib.a
-> show in finder
。
可以看到,有两个文件夹。
两个文件夹里,都有 libRelaxALib.a
这个文件。这个就是把 .m
文件实现编译成的二进制库。
还有一个比较重要的文件夹 include
,这里面放的是这个库里的头文件。
第七步 使用 lipo -create 模拟器 lib.a路径 真机 lib.a路径 -ouput 存储新的路径/newLib.a
命令。
为什么要用这个命令?
因为在编译生成库的时候,我们的选择只能是单一的模拟器或者真机。
在模拟器下编译的包只能跑在模拟下。
在真机下编译的包只能跑在真机下。
使用 lipo -info lib.a路径
查看包支持的架构。
得到的结果是 : i386 和 x86_64 ,分别是 32 位和 64 位操作系统的架构。
而在真机下 command + b 编译的包支持的架构则是 armv7 & armv7s & arm64。
armv7 是 iPhone 4s 的 CPU 架构。
armv7s 是 iPhone5 & iPhone 5c 的 CPU 架构。
arm64 则是 iPhone5s 以及以上的 CPU 架构了。
所以,可以通过 lipo -info xxx.a
的命令来查看库支持的架构。
第八步,将两种架构的包合并在一起,变成真机和模拟器都可以使用的包。
使用 lipo -create 真机.a路径 模拟器.a 路径 -output 组合包.a 路径
合并两种框架后的新包,放在桌面了。
可以使用 lipo -info
命令来查看此包支持的 CPU 架构。
lipo -info newLib.a
第九步,使用我们刚编译 + 合并 完成可以跑在真机 & 模拟器上的 .a 包。
创建一个新的项目
然后使用包里定义好的功能即可。
.framework 静态库制作
.a
是静态库 .dylib
是动态库。
.framework
是动态库也可以是静态库。
为什么有 .a
静态库了,还要出一个 .framework
静态库呢?
个人感觉,在使用层面上。
.a
静态库的使用,必须是.h(include 文件夹)
+.a 文件
+bundle
三个东西。
如果使用.framework
静态库的话,使用起来很方便。
这里主要说明 .framework
静态库的制作步骤。
第一步,创建一个 .framework项目
创建好之后的文件夹结构
第二步:framework 的一些基本参数配置
第三步,创建自己的包文件。
第四步:配置哪些头文件可以被使用包的项目导入
在 framework 本身里面,如果没有把 .h 头文件添加到 pulbic 节点,而在 '库名.h' 文件中导入这个头文件。
在库本身编译的过程中,不会有任何问题。
但是在把库给其他项目使用的时候,会报头文件找不到的错误?
那这个 private 的节点有什么作用吗?隐藏了头文件,对库自己也隐藏了?
第五步,在框架自己生成的 MyFirstFrame.h 文件里导入头文件
#import <MyFirstFramework/PrivatePerson.h>
#import <MyFirstFramework/PublicPerson.h>
格式 :#import <框架名/文件.h>
第六步,分别选择模拟器和设备,进行 command + b 编译
第七步:将模拟器包和真机包合并
补充,合并的不是MyFirstFramework.framework
。
MyFirstFramework.framework
可以理解成一个文件夹。
合并的是此文件夹里的 MyFramework
。
第八步,把合并好的 MyFirstFramework替换到任意一个包里的 MyFirstFramework
什么意思?
我们可以看一下 MyFirstFramework.framework
这个文件里面的内容。
文件夹里,本来就有 headers,info.plist,modules,MyFirstFramework。这4个元素。
它们在一起组成了一个完成的 MyFirstframework.framework
的包。
我们现在用命令生成了一个新的 MyFirstFramework
文件。其他的文件对于一个完成的 MyFirstFramework.framework
包来说,是比不可少的,也是固定不变的。
我们要做的,就是把自己合并完毕后的 MyFirstFramework 替换一下就行了。
所以,随便找一个之前的不管是真机还是模拟器的MyFristFramework.framework
包文件夹,替换里面的 MyFristFramework
包即可。
第九步,使用我们刚创建的 .framework 包
一些坑特别注意
对于 .framework 包封装用命令的时候。
MyFristFramework.framework 是文件夹,只是的库代码二进制文件是文件夹内的 MyFristFramework二进制文件。
lipo -create
&lipo -info
针对的是 MyFristFramework 文件 ,而不是 MyFristFramework.framework 文件夹