一、库的简介
1.什么是库?
库是程序代码的集合,是共享程序代码的一种方式
2.库的类型?
根据源代码的公开情况,库可以分为2种类型
>开源库
公开源代码,能看到具体实现
如SDWebImage, AFNetworking
>闭源库
不公开源代码,是经过编译后的二进制文件,看不到具体实现
主要分为: 静态库,动态库
3.静态库与动态库的区别
>静态库和动态库的存在形式上的区别
静态库: .a 和.framework
动态库: .tbd(之前叫.dylib) 和 .framework
(系统的.framework是动态库,我们自己建立的.framework是静态库)
>静态库和动态库在使用上的区别
静态库:链接时,静态库会被完整的复制到可执行文件中,被多次使用就有多份冗余拷贝
动态库: 链接时不复制,程序运行时由系统动态的加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
二、静态库的应用场景
>制作SDK - 软件开发工具包(Software Development Kit)
如"百度地图",它想让开发者在应用程序中集成百度地图,但是百度又不想公布自己的技术实现,那怎么办?百度将自己的核心代码编译成静态库,对外暴露统一的接口,开发者集成静态库,并且调用静态库即可集成
>公司在开发项目时的核心代码
公司一般在开发一个项目时,肯定有一部分代码是核心代码如果任何人都可以拿到这个核心代码,那么一旦有人离职,公司的核心代码就会被泄漏,那么该如何防止这种情况的发生?公司一般都会抽出一部分核心团队成员,专门开发这部分核心代码,开发完成后,将核心代码编译成静态库给其他的程序员调用,核心成员一般很少会离职的,从而非核心成员即使离职也无法带走公司的核心代码
>静态库分为:
真机—Debug(调试)版本、
真机—Release(发布)版本、
模拟器—Debug版本、
模拟器—Release版本;
开发中一般都打包Release(发布)版本,将真机和模拟器版本合并,提供外界,后面会提供脚本方式直接生成合成版本。
三、静态库 .a创建
1.打开Xcode,选择Cocoa Touch Static Library
2.创建一个项目,例如创建一个CreatFrameWorkDemo工程
3.TestTools的 .h .m文件
#import
@interface TestTools : NSObject
-(void)sendMessageToLog:(NSString*)msg;
@end实现自定义方法
#import "TestTools.h"
@implementation TestTools
-(void)sendMessageToLog:(NSString *)msg{
NSLog(@"测试打印传入数据:%@",msg);
}
3.把TestTools类编译成.a静态库,实际上就是把.m文件编译成.a静态库,头文件(.h)我们要暴露出去
如何暴露头文件?
第一种可以直接copy过去,但是一般不会这么做
第二种工程内配置
未编译前,Products文件夹下的.a文件是红色的,编译成功就成普通黑色了
注意:注意:注意:注意:注意:注意:如果是你拖进去的文件(.h 、.m)还要做一步,找到(compile Source)然后点击(+)把 .m添加进去
4.cmd + B编译一下得到.a文件,右键Show in Finder,这时我们会在文件夹内发现我们编译好的.a文件,如下图所示
注意 : 编译时用的什么模拟器,测试的时候就用模拟器,如:用的8Plus,测试就用8Plus
5.测试
创建工程,把刚才生成的.a及.h文件放在一个如TesTools的文件夹内,文件夹拖入工程内,引入头文件,调用方法
四、编译问题
上面我们使用的模拟器是iPhone 8 Plus,我们切换下模拟器,使用iPhone 7、iPhone 6、iPhone 5s测试一下,cmd + B编译一下即可,发现编译都能通过,没有问题(每编译一次.a文件都是重新生成的),但是换了iPhone 5( Xcode 9 就没有iPhone 5模拟器了,可以忽略了),编译后发现报错了报错信息如下:
在切换到真机(还是之前编译的.a文件),编译后发仍旧报错,报错信息如下:
以上测试,我们发现结果 : 我们的.a文件目前只支持iPhone 5s及其后面的模拟器设备,iPhone 5及以前的设备并不支持,真机设备不支持
分析原因:
1.首先每一个设备都有自己的CPU
2.每一个静态库都有自己支持的CPU架构和不支持的CPU架构
3.如何查看静态库支持哪些CPU架构命令行 : lipo -info 静态库名称终端执行命令:
lipo -info libCreatFrameWorkDemo.a
打印结果:
总结一些常见模拟器&真机所使用的CPU架构
模拟器32位处理器测试需要i386架构,
模拟器64位处理器测试需要x86_64架构
真机32位处理器需要armv7,或者armv7s架构
真机64位处理器需要arm64架构。模拟器使用的CPU架构
i386: iPhone 4s ~ iPhone 5 : i386
x86_64:iPhone 5s ~ iPhone 8plus :真机设备CPU架构
armv6设备: iPhone, iPhone2, iPhone 3G,第一代、第二代iPod Touch
armv7设备: iPhone 3GS,iPhone 4,iPhone 4S,iPad ,iPad 2,iPod Touch 3G,iPod Touch 4
armv7s设备:iPhone 5、iPhone 5c,iPad4;
arm64设备: iPhone 5S,iPad Air,iphone6 ~ iPhone 8plus
所以我们上面的.a静态库只支持 x86_64 的CPU架构(因为我们当时是在iPhone 8 Plus模拟器上编译的),其他设备运行时都会报错,要解决这个问题,就必须我们的.a文件支持所有的模拟器和真机设备,也就是同时支持i386、x86_64、armv7、armv7s、arm64 CPU架构,但是其实目前我们只用支持i386、x86_64、armv7s、arm64就可以。
支持所有模拟器方法:
设置Build Active Architecture Only中的Debug为NO,Yes表示只编译选中模拟器设备对应的架构,No则为编译所有模拟器设备支持的cup架构,所以设置为NO即可 , cmd + B编译 终端 lipo -info 测试打印:
哎呦,我擦怎么还是只支持 x86_64呢,哈哈,那是因为我用的是xcode 9以上, 没有iphone 5 模拟器了,所以编译后也就只支持 x86_64
真机支持方法:
选择真机编译一下,发现原文件夹中多了一个文件夹,即Debug-iphoneos,这个就是真机运行时生成的.a静态库,终端打印一下,看它支持哪些CPU架构
发现支持armv7 和 arm64,支持armv7的话,那么在armv7s上也能跑,现在很少有人专门配置armv7s,因为iPhone 5和5c现在很少见了
制作一个即同时支持模拟器和真机的.a文件
合并我们上面支持模拟器的.a文件和支持真机的.a文件,终端命令:
lipo -create 静态库1名 静态库2名 -output 新静态库名称
现在我们这个新的.a静态库已经支持所有模拟器的设备和真机设备的CPU架构了
六、制作静态库的注意点
(1)注意:
无论是 .a 静态库还是 .framework 静态库,最终需要的都是:二进制文件 + .h + 其它资源文件
(2).a 和 .framework 的使用区别
.a 本身是一个二进制文件,需要配上 .h 和 其它资源文件 才能使用
.framework 本身已经包含了 .h 和 其它资源文件,可以直接使用
(3)图片资源的处理
如果静态库中用到了图片资源,一般都放到一个bundle文件中,bundle名字一般跟 .a 或 .framework 名字一致
bundle的创建:新建一个文件夹,修改扩展名为 .bundle 即可,右击bundle文件,显示包内容,就可以往bundle文件中放东西
建议:自己制作的静态库中要用到的图片资源,不建议直接以png的后缀名方式拖到项目中使用,而是推荐使用放到bundle文件中。这样可以避免静态库的图片名和使用静态库的项目中存在的图片产生冲突。
1)新建一个文件夹,把需要打包的资源图片放在里面,例如:
2)修改扩展名为 .bundle,敲回车,点击添加。例如:
(4)多文件处理
如果静态库需要暴露出来的 .h 比较多,可以考虑创建一个主头文件(一般 主头文件 和 静态库 同名)
在主头文件中包含所有其他需要暴露出来的 .h 文件
使用静态库时,只需要#import 主头文件
实际上苹果官方就是这么做的,例如:#import
(5)静态库中包含了Category(分类)
如果静态库中包含了Category,有时候在使用静态库的工程中会报“方法找不到”的错误(unrecognized selector sent to instance)
解决方案:在使用静态库的工程中配置Other Linker Flags为-ObjC
补充:
在使用.a 静态库时,有些 .h 文件其实不用导入工程。例如:
静态库工工程:
BTest在ATest.m中 import 的,这样我们编译出来的 .a库,在项目使用的时候,就不需要把 BTest.h 添加到工程,只需要添加ATest.h 就可以了。
如下图,也是在 CeshiDemo.m 中 import 的ATest.h 所以就项目工程只需要添加了一个CeshiDemo.h 文件。