IOSiOS开发基础

# iOS基础 # 认识库(动态库、静态库)

2018-11-30  本文已影响66人  就叫yang

认识库

分清『 .framework 和 .a 』、『 动态库和静态库』、『 .tbd 和 .dylib』 等,.framework 不一定就是动态库

1、库(Library)

库是指一段编译好的二进制代码,并提供头文件供别人使用。

2、动态库(Dynamic library)

动态库也称动态链接,是在程序编译时不会被链接到目标代码中,直到可执行文件被执行过程中才被加载调用,即按需加载。

1、常见以 .tbd 或 .dylib 或 .framework 结尾。(默认在.app包内的Framework文件夹中)

2、动态库最低支持版本 8.0

3、动态库存储结构

当App依赖的第三方库采用动态库形式链接,编译器链接时,将第三方库相对引用,存储于App代码区域,真实的依赖资源存储于操作系统或各个App共用路径下。App启动时,只加载需要的资源到App寻址地址空间,即按需索取。其流程如下图

image

4、

App之间共用库,但是苹果本身是强制不允许的(进程间共享动态库是不允许的,iOS上的动态库只能是私有的,因此我们仍然不能将动态库文件放置在除了自身沙盒以外的其它任何地方。)

但iOS8之后,开放了App Extension功能,可以为一个应用创建插件,这样主app和插件之间共享动态库还是可行的。

5、

签名:动态库都有签名

比如我们在.app包里可以看到 _CodeSignature 会出现在很多包含非系统资源的目录级,这个其实就相当于资源签名,也是为了防止热更新等操作。

6、

OC和Swift 都是C编写的,编译后都是.o文件 ,为什么混编的时候不能用动态库,只是因为苹果不允许OC Swift混编成库而已。。。

7、

@import 和 #import的区别

#import 防止重复导入,
#import 相当于直接导入对应文件,而@import相当于引入一个对应文件的地址,需要使用的时候再去引入使用
@import 引入某个框架下得某个文件可以不需要明确框架,会自动引入。
#import 编译会慢一点

import 中得 <> 和 "" 的区别  查找路径优先级不同,<> 优先查找系统层再找用户自定义层,""相反 

import

动态库引入其他动态库的时候要用@import

对于相同路径的动态库,系统只会加载一次

3、静态库(Static library)

对于一个静态库而言,其实已经是编译好的了,类似一个 .o 的集合,在 build 的过程中只会参与链接的过程,而这个链接的过程简单的讲就是合并,并且链接器只会将静态库中被使用的部分合并到可执行文件 ( XXX.app 包内的exec 可执行文件 ) 中。

1、常见以.a或.framework结尾。

2、静态库存储结构

当App依赖的第三方库采用静态库形式链接,编译器链接时,将收集编译好代码和第三方库,存储于App代码区域,即这些资源是App可执行文件的一部分。App启动时,存储于App代码区域的代码将加载到App寻址地址空间。其流程如下图

image

4、动态库 VS 静态库

这两个东西都是编译好的二进制文件。就是用法不同而已。

从上面的两张图可以看出:

1、当程序在启动的时候,链接器会将静态库中被使用的部分合并到可执行文件 ( XXX.app 包内的exec 可执行文件 ) 中。相比于 动态库 将花费更多的启动时间和内存消耗。还会增加可执行文件的大小。

app 可执行文件: 这个目标 app 可执行文件就是 ipa解压缩后,再显示的包内容里面与app同名的文件(exec文件)。

2、对于动态库而言,在编译链接的时候,只会将动态库被引用的头文件添加到目标 app 可执行文件,区别于静态库,动态库 是在程序运行的时候被添加另外一块独立于app的内存区域。


举例:

假设 UIKit 编译成静态库和动态库的大小都看成 1M , 加载到内存中花销 1s . 现在又 app1 和 app2 两个 app。倘若使用静态库的方式,那么在 app1 启动的时候, 需要花销 2s 同时内存有 2M 分配给了 app1.同样的道理 加上 app2 的启动时间和内存消耗,采用静态库的方案,一共需要花销 4s 启动时间、4M 内存大小、4M 安装包大小。那么换成动态库的时候,对于启动和 app1 可能花费一样的时间,但是在启动 app2 的时候 不用再加载 UIKit 动态库 了。减少了 UIKit 的重复 使用问题,一共花销 3s启动时间、3M 内存大小、4M 安装包大小。

两者都是由*.o目标文件链接而成。都是二进制文件,闭源。

iOS 8 之前不支持动态FrameWork,iOS 8 之后添加了动态库的支持,主要原因是ExExtension 和 App 作为两个分开的可执行文件,同时需要共享代码,这种情况下动态库的支持就是必不可少的了.但是这种动态 Framework 和系统的 UIKit.Framework 还是有很大区别。系统的 Framework 不需要拷贝到目标程序中,我们自己做出来的 Framework 哪怕是动态的,最后也还是要拷贝到 App 中(App 和 Extension 的 Bundle 是共享的),因此苹果又把这种 Framework 称为 Embedded Framework。

Swift 跟着 iOS8 / Xcode 6 同时发布的,如果要在项目中使用外部的代码,可选的方式只有两种,一种是把代码拷贝到工程中,另一种是用动态 Framework.使用静态库是不支持的.
造成这个问题的原因主要是 Swift 的运行库没有被包含在 iOS 系统中,而是会打包进 App 中(这也是造成 Swift App 体积大的原因),静态库会导致最终的目标程序中包含重复的运行库.同时拷贝 Runtime 这种做法也会导致在纯 ObjC 的项目中使用 Swift 库出现问题。

5、.framework VS .a


.a是一个纯二进制文件,不能直接拿来使用,需要配合头文件、资源文件一起使用。在 iOS 中是作为静态库的文件名后缀。

.framework中除了有二进制文件之外还有资源文件,可以拿来直接使用。

在不能开发动态库的时候,其实 『.framework = .a + .h + bundle』。而当 Xcode 6 出来以后,我们可以开发动态库后『.framework = 静态库/动态库 + .h + bundle』

6、.tbd VS .dylib

 .dylib 就是动态库的文件的后缀名。
 
 xcode 7.0 以后 导入系统提供的动态库 就不再有.dylib了 取而代之的就是 .tbd
 
 而 .tbd(存储跨平台模块映射的文本文件) 其实是一个YAML本文文件,描述了需要链接的动态库的信息。主要目的是为了减少app 的下载大小

7、搜索路径 (Search path)

搜索路径是指程序链接时,到哪个位置寻找库。

@executable_path:表示可执行程序所在的目录。
@loader_path:表示每一个被加载的 binary (包括App, dylib, framework, plugin等) 所在的目录。
@rpath:是一个保存着一个或多个路径的变量,告诉连接器到哪里找库。

8、Mach-O Type

全称 Mach Object Type ,是一种用于存储可执行文件,目标代码,动态库,内核转储的文件格式。

Xcode中查看Target 的 Build Settings 可以发现可以选择,里面就包含了动态库和静态库。

在制作 framework 的时候需要选择这个 Mach-O Type.

9、Embedded VS. Linked

工程General中 有两个地方可以加库

Embedded Binaries

Embedded 的意思是嵌入,但是这个嵌入并不是嵌入 app 可执行文件,而是嵌入 app 的 bundle 文件。当一个 app 通过 Embedded 的方式嵌入一个 app 后,在打包之后解压 ipa 可以在包内看到一个 framework 的文件夹,下面都是与这个应用相关的动态framework


linded feameworks and libraries 

在 linded feameworks and libraries 这个下面我们可以连接系统的动态库、自己开发的静态库、自己开发的动态库。对于这里的静态库而言,会在编译链接阶段连接到app可执行文件中,而对这里的动态库而言,虽然不会链接到app可执行文件中,如果你不想在启动的时候加载动态库,可以在 linded feameworks and libraries 删除,并使用dlopen加载动态库。(dlopen 不是私有 api。)

- (void)dlopenLoad{
    NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework/Dylib",NSHomeDirectory()];
    [self dlopenLoadDylibWithPath:documentsPath];
}

- (void)dlopenLoadDylibWithPath:(NSString *)path
{
    libHandle = NULL;
    libHandle = dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);
    if (libHandle == NULL) {
        char *error = dlerror();
        NSLog(@"dlopen error: %s", error);
    } else {
        NSLog(@"dlopen load framework success.");
    }
}

10、其他

.tbd 文件格式: 存储跨平台模块映射的文本文件,Xcode7以后 .dylib格式 动态库替换为.tbd格式。

framework是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。

.a 文件

.o 文件

_CodeSignature 目录

.car 文件

Framework目录

der文件

exec文件

.bundle

上一篇下一篇

猜你喜欢

热点阅读