库介绍app
库从本质上来讲是一种可执行代码的二进制格式,能够被载入内存中执行。库分静态库和动态库两种。框架
iOS中的静态库有 .a 和 .framework两种形式;动态库有.dylib 和 .framework 形式,后来.dylib动态库又被苹果替换成.tbd的形式。iphone
静态库与动态库的区别ide
静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被连接到目标代码中,程序运行时将再也不须要改静态库;而动态库在程序编译时并不会被连接到目标代码中,只是在程序运行时才被载入,由于在程序运行期间还须要动态库的存在。ui
总结:同一个静态库在不一样程序中使用时,每个程序中都得导入一次,打包时也被打包进去,造成一个程序。而动态库在不一样程序中,打包时并无被打包进去,只在程序运行使用时,才连接载入(如系统的框架如UIKit、Foundation等),因此程序体积会小不少,可是苹果不让使用本身的动态库,不然审核就没法经过。spa
建立.a静态库3d
第一步,新建工程。通常使用工程名就使用库的名称,好比我这里用FMDB来建立静态库,个人工程名就取名为FMDB,建立的.a静态库就是libFMDB.a。code
第二步,删除系统默认建立的【FMDB.h】和【FMDB.m】文件,导入须要打包的源文件。blog
第三步(方式一),修改项目配置图片
点击上图中的【3】,弹出的列表中选择【New Headers Phase】,打开【Headers (0 items)】,点击左下角的【+】,选择全部的.h文件。
第三步(方式二),修改项目配置
第四步,修改导出product配置
第五步,修改编译指令集
模拟器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64
真机:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64
若是第五步这里,设置为YES,那么编译出来的.a静态库就只包含当前设备的指令集。
举个例子:若是咱们选择iPhone 5模拟器【Command+B】编译,则编译出来的.a静态库只能用iPhone4s~5模拟器跑程序,用iPhone5s~6plus,则会报找不到x86_64的libFMDB库。
设置为NO,则会把全部指令集的都打包合并。
第六步,编译(快捷键【Command+B】
编译时,须要用模拟器和真机各编译一次,这样Products目录下的libFMDB.a静态库才会变为黑色,右键show in Finder,能够进入Products目录下。
为何须要用模拟器和真机各编译一次呢?
能够看到Products目录下有【Release-iphoneos】和【Release-iphonesimulator】两个文件件。前者里面是真机使用的.a静态库,后者是模拟器使用的.a静态库。
注意:若是步骤四中,不将Build Configuration改成Release,则打包出来的静态库会存于【Debug-iphoneos】和【Debug-iphonesimulator】两个文件夹下。
咱们通常都使用Release模式,由于程序最终发布以后是Release版的,因此静态库也是在Release模式下使用。
若是想要通用须要将模拟器使用的静态库与真机使用的静态库合并成一个静态库,可使用终端命令来实现。命令格式:
lipo -create 第一个.a文件的绝对路径 第二个.a文件的绝对路径 -output 最终的.a文件路径。
本文中使用的命令以下:
lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphoneos/libFMDB.a /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphonesimulator/libFMDB.a -output /Users/harvey/Desktop/libFMDB.a
补充:通过屡次实践,第三步的操做省略,依然能够导出可正常使用的包。
若是静态库中有category类,则在使用静态库的项目配置中【Other Linker Flags】须要添加参数【-ObjC]或者【-all_load】。
建立framework静态库
第一步,新建项目
第二步,删除系统默认建立的【FMDB.h】和【FMDB.m】文件,导入须要打包的源文件。
第三步,修改项目配置
首先,设置须要暴漏的头文件
这里须要注意的是暴露出来的头文件中import的其余类也得添加到public中暴露出来。
若是不想将import的类暴露出来,那么在头文件中用@class 而后在对应的.m文件中再import。
而后设置编译模式,在Xcode菜单【Product】--->【Scheme】--->【Edit Scheme...】中
设置编译出的静态库包含的指令集
最后修改生成的Mach-O格式
第四步,编译生成静态库
编译时,须要用模拟器和真机各编译一次,这样Products目录下的libFMDB.a静态库才会变为黑色,右键show in Finder,能够进入Products目录下。
第五步,合并模拟器版framework和真机版framework
合并的命令同上面类似,不一样之处是:framework静态库合并的不是framework,而是framework下的一个二进制文件,即上一步图中标记的文件。
lipo -create 第一个framework下二进制文件的绝对路径 第二个framework下二进制文件的绝对路径 -output 最终的二进制文件路径。
本文中使用的命令以下:
1
|
lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphonesimulator/FMDB.framework/FMDB /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphoneos/Release-iphoneos.framework/FMDB -output /Users/harvey/Desktop/FMDB
|
最后将任何一个framework中的二进制文件替换成合并后的二进制文件便可。
把framework添加到要使用的项目中便可使用。
注意:若是建立的framework中使用了category类,则在使用framework的项目配置中【Other Linker Flags】须要添加参数【-ObjC]或者【-all_load】。
若是使用framework的使用出现【Umbrella header for module 'XXXX' does not include header 'XXXXX.h'】,是由于错把xxxxx.h拖到了public中。
若是出现【dyld: Library not loaded:XXXXXX】,是由于打包的framework版本过高。好比打包framework时,选择的是iOS 9.0,而实际的工程环境是iOS 8开始的。
若是建立的framework类中使用了.dylib或者.tbd,首先须要在实际项目中导入.dylib或者.tbd动态库,而后须要设置【Allow Non-modular Includes ....】为YES,不然会报错"Include of non-modular header inside framework module"。
补充:打包成的静态库确定是比源码类要大不少的,由于是由不一样指令集不一样设备的版本合并成的。因此若是你很在乎你的app大小,而且也不是很须要打包成静态库的话,仍是用原始类吧。
framework静态库中是能够包含图片资源的;而.a静态库中不能包含图片资源,只能另外建立一个目录存放。
填坑记录
上面的注意里提到了一些坑,以及解决办法。这里再记录一些:
1.framework中用到了NSClassFromString,可是转换出来的class 一直为nil。
先来看一下这个API的官方描述
什么意思呢?若是转换出来的class为nil,有两种状况:一种状况是这个类不存在;第二种状况是这个类尚未被load。因此通常出现问题,都是第二种状况。
怎么解决这个问题呢?在主工程的【Other Linker Flags】须要添加参数【-ObjC]便可。