iOS静态库 【.a 和framework解析】【超详细】
一、什么是库?
库是共享程序代码的方式。
库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。
iOS中的静态库有 .a 和 .framework两种形式;动态库有.dylib 和 .framework 形式,后来.dylib动态库又被苹果替换成.tbd的形式。
二、静态库与动态库的区别?
静态库: 链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
动态库: 链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。[ios暂时只允许使用系统动态库];
静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。
总结:同一个静态库在不同程序中使用时,每一个程序中都得导入一次,打包时也被打包进去,形成一个程序。而动态库在不同程序中,打包时并没有被打包进去,只在程序运行使用时,才链接载入(如系统的框架如UIKit、Foundation等),所以程序体积会小很多,但是苹果不让使用自己的动态库,否则审核就无法通过。
三、iOS里静态库形式?
.a和.framework
四、iOS里动态库形式?
.dylib和.framework
五、framework为什么既是静态库又是动态库?
系统的.framework是动态库,我们自己建立的.framework是静态库。
六、a与.framework有什么区别?
.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。
.a + .h + sourceFile = .framework。
建议用.framework.
七、为什么要使用静态库?
方便共享代码,便于合理使用。
实现iOS程序的模块化。可以把固定的业务模块化成静态库。
和别人分享你的代码库,但不想让别人看到你代码的实现。
开发第三方sdk的需要。
八、制作静态库时的几点注意:
1注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。
2图片资源的处理:两种静态库,一般都是把图片文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把它改名为.bundle就可以了,右键,显示包内容可以向其中添加图片资源。
3category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。
4如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。
九、创建.a静态库
第一步,新建工程。一般使用工程名就使用库的名称,比如我这里用LIB来创建静态库,我的工程名就取名为LIB,创建的.a静态库就是LIB.a。
第二步,删除.m文件,保留.h文件, 一般静态库都有一个总的.h文件,方便外部导入头文件。然后导入需要打包的源文件。
第三步,先用真机,编译一次,再用模拟器编译一次。就可以生成.a文件(必须先用真机要不然,不能生成)。
第四步,Xcode生成的.a文件默认没有导出.h文件。需要自己添加。
第五步,导出Products静态库的配置(其实不用设置此步骤,如果真机编译的话,生成导出的时候系统默认会变成Releasse[但是模拟器不会(如果不改这里 得需要把Debug设置为NO)])
注意:如果第五步中,不将Build Configuration改为Release,则打包出来的静态库会存于【Debug-iphoneos】和【Debug-iphonesimulator】两个文件夹下。
我们一般都使用Release模式,因为程序最终发布之后是Release版的,所以静态库也是在Release模式下使用。
第六步,合成模拟器的架构【默认:模拟器编译只会生成对应的1种架构,真机编译会合成两种架构】
如果第六步这里,设置为YES,那么编译出来的.a静态库就只包含当前设备的架构。
举个例子:如果我们选择iPhone 5模拟器【Command+B】编译,则编译出来的.a静态库只能用iPhone4s~5模拟器跑程序, 用iPhone5s~6plus,则会报找不到x86_64的libFMDB库。
设置为 NO 之后,【Command+B】不管选择哪个【模拟器】,则都会把【386 : 32位架构 4S ~ 5】【x86_64 : 64位架构 5S ~ 现在的机型】的架构都打包合并。
【注】【真机】不设置[Build Active Architecture Only]也默认会自动合并的armv7 和amr64架构 。但是armv7s架构被苹果放弃了,真机要想合并armv7s的话需要进行如下操作再编译。(其实没必要设置这个)
第七步,合并架构【真机和模拟器】
真机和模拟器合并: lipo -create 静态库1.a(路径) 静态库2.a(路径)-output 新静态库.a
第八步,资源包的问题
1. 静态库的资源, 都应该放到后缀为.bundle的文件夹中 --> 避免文件与本地文件重名被覆盖, 导致加载资源文件出错【注:要加载bundel路径】
2. 静态库打包时, 并不会打包资源文件 --> 需要手动拖出去
一. 经典报错:
找不到符号在XX架构上
Undefined symbols for architecture x86_64(armv7/armv7s/amr64/i386)
二. 架构的分类
1、模拟器架构: 2种
i386 : 32位架构 4S ~ 5
x86_64 : 64位架构 5S ~现在的机型
2、真机架构: 3种
armv7 : 32位架构 3GS ~ 4S
armv7s: 特殊的架构 5 ~ 5C (此架构有问题, 有的程序变得更快, 有的程序变得更慢)
amr64 : 64位架构 5S ~现在的机型
64位/32位: 内存寻址不同
三. 如何查看静态库架构
找到Products文件夹, 如果.a文件是黑色, 右键打开 到Products文件夹
终端中lipo -info
Generic iOS Device编译出来的OS可用, 有2种架构:armv7/ arm64 (不包含armv7s: 特殊的架构)
iPhone6S模拟器编译出来的: x86_64
iPhone4S模拟器编译出来的: i386
(不设置Build Active Architecture Only的情况下真机编译2种架构, 模拟器编译:对应的1种架构)
四. 合成架构
一般来说, 只需要前两步即可
1. 模拟器架构的合成: Target --> Build Settings --> Build Active Architecture Only(是否只编译当前架构) --> Debug 改为NO(改为NO, 模拟器就可以直接合成2种架构)
2. 真机和模拟器合并: lipo -create 静态库1.a 静态库2.a -output 新静态库.a
3.* armv7s这个架构, 在2014年10月份的xcode版本更新中, 取消了默认导出此架构. 可以不用支持此架构.
如果要支持, 需要手动添加3个架构.
五. Debug和Release版本
一般来说, 我们应该发布的是release版本.
debug:调试版本, 系统本身也会有一些调试代码. 此版本体积会稍大, 运行会稍慢
release: 发布版本, 系统会去除调试代码, 体积变小, 运行速度变快. 对用户来说没有明显的感觉
六. 到底要不要合成多个架构
真机和模拟器合成的好处: 调试会非常方便, 缺点是体积会变大(一种架构就占用一部分体积).
真机和模拟器不合成的好处:体积小, 缺点是调试稍显麻烦.
七. 资源包的问题
1. 静态库的资源, 都应该放到后缀为.bundle的文件夹中 --> 避免文件重名被覆盖, 导致加载资源文件出错
2. 静态库打包时, 并不会打包资源文件 --> 需要手动拖出去
十、创建framework静态库
第一步、新建工程。一般使用工程名就使用库的名称
第二步、导入需要打包的资源文件,同时把资源文件需要外界访问的.h文件导入到系统推荐的.h中
第三步、真机,模拟器编译一下。可能会需要输入AppleID 。导出的文件没有包含.h
第四步、导出.h
第五步、可以查看一下 没合并模拟器架构之前包含几个同.a(可跳过此步)(真机包含两个,模拟器包含一个)
第六步、合成架构【同.a五六步详细看上边】
第七步,合并架构【真机和模拟器】【注意 合并之后的动态/静态库要与原来的名称一致。不然用的时候编译报错】
第八步、动态库变静态库【默认是动态】好处是将来使用时不需要设置添加动态库(也就是下边的方法)
最后步、
Framework制作后,默认是动态库.使用时,需要设置一下: Tarteg --> General --> Embedded Binaries -->需要添加对应的动态库 【注意 要是制作的时候更改为静态库的话,就不用执行此方法】
下一篇: iOS开源项目:JSONKit