dynamic与staic framework的制作注意点及差异

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/denggun12345/article/details/86156040

我们自己制作的framework根据mach-o分为dynamic与static两种,此处的dynamic名义上是动态,但并非真正的动态库,只有系统的库才是真正的动态库,我们自己做的framework实质上都是静态库(因为动态库可以多个app公用的,这样就违背了沙盒的实质,而我们作为开发者开发的framework不会打破这种机制),也可以叫做embeded即嵌入式的framework。

framework的制作流程大体相同,且都能将资源文件(图片、xib、文件等)打包进framework,但是在用相同的workspace和project以联编的方式来制作这两种framework时,又有很大的差异,在此也趟了不少坑:

相同点:

1、制作流程相同

2、资源文件都要以bundle的形式添加到framework

   2.1》xib文件:需要注意的是xib资源要转化成nib再添加到bundle,如果不转换为nib则在调用到此framework的库的工程里会报错找不到xib,因为xcode加载xib的实质是加载nib,而bundle文件不会再进行编译,所以在加入bundle文件时要转化为nib文件。

xib转化为nib要通过命令行的方式转化:ibtool --errors --warnings --output-format human-readable-text --compile YHTestSevenCell.nib YHTestSevenCell.xib

不同点:

主要是在目标工程的配置的不同:

1》在使用到embeded framework的工程中,需要将此framework添加到General的Embedded Binaries中,否则会报错(只有在真机的时候会报错;模拟器不报错,运行正常):

dyld: Library not loaded: @rpath/MyFramework.framework/MyFramework

  Referenced from: /var/containers/Bundle/Application/FA25E818-DB80-4C09-9B97-31B7C600CD14/MainProject.app/MainProject

  Reason: image not found

而static framework不需要Embedded Binaries中添加。

2》static framework需要在  Build Phases的New Copy Files Phase中添加此静态库

    而embeded的framework不需要加这个

3》加载资源文件bundle的路径(方式)不一样,以加载同一张图片为例:

  3.1》embeded framework:

        NSBundle *bundle = [NSBundle bundleForClass:[YHTestView class]];

        NSURL *url = [bundle URLForResource:@"Test" withExtension:@"bundle"];

        NSBundle *imageBundle = [NSBundle bundleWithURL:url];

        NSString *path = [imageBundle pathForResource:@"80" ofType:@"png"];

        imageView.image = [UIImage imageWithContentsOfFile:path];

 3.2》static framework从mainundle取图片:

        NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"YHTestFramework.framework/Test" ofType:@"bundle"];

        NSBundle *imageBundel = [NSBundle bundleWithPath:bundlePath];

        NSString *path = [imageBundel pathForResource:@"80" ofType:@"png"];

        imageView.image = [UIImage imageWithContentsOfFile:path];

4》nib文件的引用文件差异:

nib文件中的控件在对应文件中有引用(拉线),embeded framework直接按正常方法使用,正常,而同样的场景static framework会报错 Unknown class YHTestFiveCell in Interface Builder file.2019-01-08 15:11:26.798509+0800 YHTestProject[30029:2529980] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UITableViewCell 0x100889800> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key leftIMV.'

报错原因:

由于静态框架采用静态链接,linker会剔除所有它认为无用的代码。linker不会检查xib文件,因此类是在xib中引用,而没有在OC代码中引用,linker将从最终的可执行文件中删除类。这是linker的问题,不是框架的问题(编译静态库也会有这个问题(指的应该是.a))。苹果内置框架不会发生这个问题,因为他们是运行时动态加载的,存在于ios设备固件中的动态库是不可能被删除的。

简言之:

只在xib中有引用,而在其他oc代码中没有用到的类,才会被linker剔除

解决:

4.1》、让框架的最终用户关闭linker的优化选项,通过在他们的项目的Other Linker Flags(Build Setting -> Other Linker Flags)中添加-ObjC和-all_load

4.2》、在框架的另一个类中加一个该类的代码引用,但依旧要加-ObjC

  在这里,我用第二种方法,因为是cell的xib,在其他oc代YHTestFiveTableViewController.m中调用了该类,故在使用该静态库的工程中加-ObjC即可

注:如果库中有category也需要对Other Link Flags 做处理

在这里顺变介绍下Other Linker Flags

C程序的,从C代码到可执行文件经历的步骤:

源代码-》预处理器-》编译器-》汇编器-》机器码-》链接器-》可执行文件

源文件经过一系列处理后,会生成.objc文件,一个项目有很多.objc文件,且这些.objc之间会有各种联系,链接器做的事就是把这些目标文件和所用的库链接在一起形成一个完整的可执行文件,这就是为何上边6在编译过程中没事而在运行的时候报错。Other Link Flags设置的内容其实就是链接器工作时除了默认参数外的其他参数。

Other Linker Flags常用参数:

1》-ObjC:这个flag告诉链接器把库中定义的OC类和Category或nib都加载进来,编译后app会变大,以为加载了很多不必要的文件导致可执行文件变大。但是如果静态库中有类和分类只有加入这个flag才行;但是当静态库中只有分类而没有类时,-ObjC就失效了,这时需要加-all_load 或 -force_load了

2》-all_load:会强制链接器把目标文件都加载进来,即使没有objc代码。

      弊端:当使用了不只一个静态库文件,会遇到ld:duplicate symbol错误,因为不同库里会有相同的目标文件,针对这个问题有两种解决方法:1》用命令行就行拆包2》用另一个参数-force_load

3》-force_load:

   这个flag与-all_load其实是一样的,只是-force_load需要指定要进行全部加载的库的文件路径,这样只是完全加载了一个库文件,不影响其余文件按需加载

      

猜你喜欢

转载自blog.csdn.net/denggun12345/article/details/86156040