库是共享程序代码的方式,一般分为静态库和动态库
-
静态库:链接时完整拷贝至可执行文件中,被多次使用就有多份冗余拷贝。iOS静态库形式:.a和.framework
-
动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。iOS动态库形式:.tbd(之前叫.dylib)和framework
-
.a和.framework区别
-
.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。
-
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。
-
.a + .h + sourceFile = .framework。
-
建议用.framework.
-
创建framework
1. 创建framework
2. 修改framework类型
创建的framework默认为动态库,在build settings搜索mach,将Mach-O Type 改为 Static Library(静态库)类型
3. Build Active Architeture only 改为NO,指定只对当前连接设备所支持的指令集编译。当设置为YES时是为了debug编译的速度更快,它只会编译当前的architecture版本;当设置为NO时,会编译所有的版本,所以一般debug设置为YES,release设置为NO以适应不同设备.
4. iOS Deployment Target ,静态库需要支持的最低版本号,要小于等于主项目的版本号
5. 如果要静态库支持bitcode,则在build settings搜索Custom,在Other C Flags添加-fembed-bitcode
6. 把用到的文件及文件夹拖到里面,将需要公开的头文件放到Public里,使用cocopods可以自动管理第三方库
7. 将framework的Run Scheme设置为Release模式,编译生成真机和模拟器framework,生成两个FrameworkProject.framework文件,然后把两个FrameworkProject.framework文件中的FrameworkProject用命令合成一个。
-
注意:1. xcode12编译过程中可能会有如下报错:
The linked framework ‘xxxx.framework‘ is missing one or more architectures require by this target:armv7
解决方法:在Build Settings-Excluded Architectures 中添加如下代码:armv7,重新编译即可
-
注意:2. 原来的打包脚本分别对应 模拟器和真机 , 更新xcode12之后,在合成为fat包时,出现这个错误
have the same architectures (arm64) and can't be in the same fat output file
解决方法:在Build Settings-Excluded Architectures 中添加如下代码:arm64。
脚本合并真机和模拟器: lipo -create 第一个framework的二进制文件的绝对路径 第二个framework的二进制文件的绝对路径 -output 存放的路径/输出的SDK名称。最后,将这个替换掉任意一个framework里面的二进制文件,就OK了。
8. 制作静态库时的几点注意:
-
注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。
-
category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。
-
-ObjC/-all_load/-force_load
-
我们知道在Objective-C中方法调用都是在运行期确定的,所以Objective-C没有针对每个方法定义链接符号,它只对每个类创建链接符号。因此当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时出现selector not recognized的错误。设置ObjC标志后,链接器会把一个类相关的所有目标文件都加载进来,这样就解决了这个问题。由于这样做会使可执行文件体积变大,所以需要自己手动设置一下。
-
在64位ios应用环境下,在静态库中只有category而没有对应的class定义时-ObjC标志会失效(这是链接器的一个bug),这时可以使用-all_load强制加载所有目标文件 或者使用-force_load指定加载某一个包,千万不要随便使用这个参数!假如你使用了不止一个静态库文件,然后又使用了这个参数,那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件,所以建议在遇到-ObjC失效的情况下使用-force_load参数。
-
-force_load所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载。