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

认识库

分清『 .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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350