Module化

想直接了解modules更官方解释的可参考官方文档:
https://clang.llvm.org/docs/Modules.html#introduction

import 和 include

在了解Module化之前我们需要先了解一下OC的import机制。#import <SDWebImage/UIImage+Gif.h>
,日常开发中都写这样的代码,用来引用其他的头文件。在C和C++里是没有#import的,只有#include,用来包含头文件。#include做的事情其实就是简单的复制粘贴,将目标.h文件中的内容一字不落地拷贝到当前文件中,并替换掉这句include,而#import实质上做的事情和#include是一样的,只不过OC为了避免重复引用可能带来的编译错误(这种情况在引用关系复杂的时候很可能发生,比如B和C都引用了A,D又同时引用了B和C,这样A中定义的东西就在D中被定义了两次,重复了),而加入了#import,从而保证每个头文件只会被引用一次

import 导入

图片.png

预处理之后的AppDelegate
图片.png

include

include单次导入是和import是一样的,这里不再赘述
重点看下重复导入的情况

include重复导入的AppDelegate文件.png

import预编译之后的AppDelegate.m文件.png

使用include会把ViewController.h头文件拷贝两次,并且编译报错重复定义
图片.png

使用import 重复导入
import导入的AppDelegate.m文件.png

import预编译之后的AppDelegate.m文件.png

import = #pragma once + include
使用#pragma once修饰后可正常编译, 预编译后的文件也只copy一次

图片.png

具体实现原理是通过 #ifndef #define 一个头文件标记,在处理头文件引用的时候则判断该标记,如果已经定义过就不再对目标文件进行粘贴。

无论是includeimport本质都是对头文件的复制粘贴,这样就带来一个问题:当引用关系很复杂,或者一个头文件被非常多的实现文件引用时,编译时引用所占的代码量就会大幅上升, 因为被引用的头文件在各个地方都被copy了一遍。为了解决这个问题,C系语言引入了预编译头文件(PreCompiled Header),将公用的头文件放入预编译头文件中预先进行编译,然后在真正编译工程时再将预先编译好的产物加入到所有待编译的Source中去,来加快编译速度。比如iOS开发中的.pch文件就是一个预编译头文件,默认情况下,它引用了UIKit和Foundation两个头文件
于是理论上说,想要提高编译速度,可以把所有头文件引用都放到pch中。但是这样面临的问题是在工程中随处可用本来不应该能访问的东西,而编译器也无法准确给出错误或者警告,无形中增加了出错的可能性。

swift

Objective-C中,我们需要通过#import 或#include导入头文件,编译器在预处理阶段将这些头文件里面的API复制到当前文件,然后可以访问, swift缺少预处理阶段,头文件不能像 Objective-C一样使用#import 或#include导入了,但还是需要类似的操作才能访问到这些API。那么swift该怎么引用呢?

OC的编译过程

  1. 预处理
  2. 词法分析
  3. 语法分析
  4. 静态分析
  5. 生成汇编指令
  6. 汇编
  7. 链接

Swift编译

  1. 解析
  2. 语义分析
  3. Clang 导入器
  4. SIL 生成
  5. SIL 保证转换
  6. SIL 优化
  7. LLVM IR 生成

对于OC和Swift混编中,肯定会涉及到头文件的引用,swift文件中直接导入肯定是不行的!
苹果提供了两种方案来实现混编调用

1.桥接文件

调用 Objective-C 文件,主要通过桥接文件来实现,在桥接文件中导入需要暴露给 Swift模块的 Objective-C 类头文件,即可在 Swift模块中直接调用,如下图所示:

图片.png

调用 Objective-C 编写并打包封装的静态/动态库

不同于文件调用,Swift 调用 Objective-C 库可以通过 LLVM 的 Module系统来实现,Xcode 打包时默认支持Module 系统,它对当前开发者来说没有任何成本,只是 Framework 中自动生成 modulemap 文件(后文会介绍),我们主要通过这个描述文件来访问。

图片.png

桥接文件、Module 是目前我们实现 Swift 调用 OC 的主要方案,对Swift开发者来说,这两种方案的成本都比较低,桥接文件相当于我们的头文件汇总声明,而Module对调用方来说,基本是零成本

Modules

Apple于2012年引入了Module机制,不同于#includeModule采用了更高效的语义模型。用树形的结构化描述来取代以往的平坦式#include并缓存下来,生成一个树形结构的modulemap,用于描述框架、系统头文件、控制导出的范围、依赖关系、链接参数等等。
对于支持Module的模块,在编译时会被当做一个独立的编译单元,该单元只会被编译一次,编译器会维护一个已经编译的单元列表。如果在目标文件中引用到了某个Module,首先会在这个单元列表中进行查找,如果没有找到会进入编译流程并添加进来,如果找到了则直接使用已编译好的Module单元,类似于App中常用的缓存机制。在Module这个引用机制下,预处理消耗由M*N减低到了M+N的级别。
在实际使用中,可以将Module看作一个框架接入的中间件,这个中间件维护了编译单元和具体headers的路由关系,这种路由关系是通过modulemap这种形式来表达的。我们通过UIKit的modulemap来具体解释一下:

图片.png

图片.png
  • umbrella header
    我们应该非常熟悉<UIKit.h>这个文件,在modulemap中,它起到一个汇总的作用,我们查看UIKit.h这个文件,会发现它其实是对UIKit所有可调用头文件的汇总,这里主要是为了语法上的便利,避免在该文件中描述所有的头文件。
  • export*
    export *语义作用是描述所有子Module,即:假如调用方可能需要调用UIKit中所有的头文件,只需要声明UIKit即可.
  • explicit module
    explicit module语义是针对子Module进行的描述,它将Module根据实际需要拆分成了不同的子Module。即:调用方需要针对调用手势识别相关的内容,只声明UIGestureRecognizerSubclass这个Module即可。
import UIKit.UIGestureRecognizerSubclass 

Module 实践

在Xcode内开启Module支持选项
手动为工程开启支持module选项很简单,只需要将Target配置选项开启即可。

图片.png

Framework如何支持
创建支持Module的Framework

在Xcode中创建framework并支持Module也是很简单的: 在新建Framework的时候,Xcode默认在build settings中设置了Defines Module为YES:


图片.png

当你编译framework的时候,在对应路径下就已经生成了module文件,格式为:

图片.png

如果没有引用其他framework, xcode中默认不显示Products目录,在General->Frameworks and Libraries 中随便添加一个就可以显示了


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

推荐阅读更多精彩内容