iOS:Module

1. Module-最小的代码单元

一个Module是机器代码和数据的最小单元,可以独立于其他代码单元进行链接,
通常,Module是通过编译单个源文件生成的目标文件。例如,当前的test.m被编译成目标文件test.o时,当前的目标文件就代表一个Module
但是,有一个问题,Module在调用的时候会产生开销,比如我们在使用一个静态库的时候。
导入文件时如果使用include的,每次编译的时候就会编译一个我们include的头文件,导入资源的浪费。我们现在使用的import(module)导入头文件,导入的头文件会预先编译成二进制,再有文件导入时就不会重新编译。

1.1,实测module

//A.h文件
#ifdef ENABLE_A
void a() {}
#endif
//B.h文件
#import "A.h"
//module.modulemap文件
module A {
  header "A.h"
}

module B {
  header "B.h"
  export A
}
//use.c文件
#import "B.h"
void use() {
#ifdef ENABLE_A
  a();
#endif
}

我们使用clang编译

// -fmodules:允许使用module语言来表示头文件
// -fmodule-map-file:module map的路径。如不指明默认module.modulemap
// -fmodules-cache-path:编译后的module缓存路径
clang  -fmodules -fmodule-map-file=module.modulemap -fmodules-cache-path=../prebuilt -c use.c -o use.o

我们查看prebuilt->2Q2IP2MFAAABM文件可以看到两个pcm文件,这两个文件就是预编译好的,如果其他文件再引入A和B就不用重新编译了。

1.2.查看AFNetworking文件的modulemap文件

framework module AFNetworking { //声明framework的module名称为AFNetworking
//导入文件的集合
  umbrella header "AFNetworking-umbrella.h"
  export * //把引入的头文件重新导出。
  module * { export * } //把导入头文件修饰成子module,并把符号全部导出
}

其他module的操作,点这里
我们开启module之后无论我们使用include,import或者@import,编译的使用都会被优化成module形式,就是同一个文件只会被编译一次。

1.3.实操

我们创建一个framework,名字为MyOCFramework,再创建一个主工程名字为MyTestApp,打开主工程,点击file->save as workspace,保存到主工程的同一级目录下。然后打来我们的workspace,在工程中,在没有文件被选的情况下,File->Add file to 到我们的workspace。选择我们的framework。
编译我们的framework,能看到会在framework下自动生成Modules 文件.
如果我们想自定义我们的module文件,我们创建modulemap文件,然后在build setting中设置module map file的路径。
我们创建ocmodule.modulemap文件文件内容如下

framework module MyOCFramework {
  umbrella "Headers"

  export *
  module * { export * }
}

module map file设置为MyOCFramework/ocmodule.modulemap,编译成功,并在framework文件中看到module.modulemap。

2.Swift的framework和OC混编

因为在framework中没有桥接文件,所以swift代码没法直接调用oc,我们要使用module,framework已经自动帮我们实现了。
我们可以在swift代码中直接使用oc类,如果我们想在oc类中调用swift代码,我们需要通过module指定头文件#import <项目/项目-Swift.h>
如果我们不想对外暴漏我们的OC类,我们可以创建swiftmodule.private.modulemap

framework module MySwiftFramework_Private {
  explicit module MyOCClass{
      header "MyOCClass.h"
      export *
  }
}

然后在Private Module Map File 中指定路径。
我们不能通过MySwiftFramework 的module 来访问MyOCClass,但是我们可以通过
MySwiftFramework_Private来访问MyOCClass。
Private Module不是真正意义上的私有,我们可以通过MySwiftFramework_Private可以访问,只是供开发者区分。

3.Swift静态库合并

在Xcode 9.0之后,swift开始支持静态库
swift没有头文件的概念,那么我们外界使用swift中的public修饰的类和函数怎么办呢?Swift库引入了一个全新的文件.swiftModule
.swiftModule包含序列化过的AST(抽象语法树),也包含SIL(Swift中间语言,Swift Intermediate Language)。
我们可以看一下我们的framework中,Module中有一个.swiftmodule文件。
创建两个framework库,分别为MySwiftA和MySwiftB
两个库里有一个相同的类

@objc open class MySwiftTeacher: NSObject {
    public func speek() {
        print("speek!")
    }
    @objc public func walk() {
        print("walk!")
    }
}

并把两个静态库编译后的framework放到products目录下脚本

cp -Rv -- "${BUILT_PRODUCTS_DIR}/" "${SOURCE_ROOT}/../Products"

合并两个静态库

libtool -static MySwiftA.framework/MySwiftA MySwiftB.framework/MySwiftB -o libMySwiftC.a
//日志警告,两个静态库都包含MySwiftTeacher.o

我们通过ar -t libMySwiftC.a查看libMySwiftC.a中的目标文件

__.SYMDEF
MySwiftA_vers.o
MySwiftTeacher.o
MySwiftB_vers.o
MySwiftTeacher.o

我们手动组合MySwiftC库


image.png

配置build setting文件

HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/MySwiftC/MySwiftA/Headers" "${SRCROOT}/MySwiftC/MySwiftB/Headers"
OTHER_CFLAGS = $(inherited) "-fmodule-map-file=${SRCROOT}/MySwiftC/MySwiftA/module.modulemap" "-fmodule-map-file=${SRCROOT}/MySwiftC/MySwiftB/module.modulemap"
SWIFT_INCLUDE_PATHS = $(inherited) "${SRCROOT}/MySwiftC/MySwiftB" "${SRCROOT}/MySwiftC/MySwiftA"

4.OC映射到Swift方式

为了让oc代码在swift使用中规范,

4.1使用宏

NS_SWIFT_NAME(<#name#>)
NS_REFINED_FOR_SWIFT 在swift方法中, 编译器会在名称前加上
_

4.2.使用apinotes文件

官方文档
前面是项目或者sdk的名称后缀是apinotes,

---
Name: OCFramework
Classes:
- Name: LGToSwift
  SwiftName: ToSwift
  Methods:
  - Selector: "changeTeacherName:"
    Parameters:
    - Position: 0
      Nullability: O
    MethodKind: Instance
    SwiftPrivate: true
    # Availability: nonswift
    #AvailabilityMsg: "prefer 'deinit'"
  - Selector: "initWithName:"
    MethodKind: Instance
    DesignatedInit: true

5.module 相关的 build setting 参数

5.1对module自身的描述:

DEFINES_MODULE:YES/NO,module 化需要设置为 YES
MODULEMAP_FILE:指向 module.modulemap 路径
HEADER_SEARCH_PATHS:modulemap 内定义的 Objective-C 头文件,必须在 HEADER_SEARCH_PATHS 内能搜索到
PRODUCT_MODULE_NAME:module 名称,默认和 Target name 相同

5.2对外部module的引用

FRAMEWORK_SEARCH_PATHS:依赖的 Framework 搜索路径
OTHER_CFLAGS:编译选项,可配置依赖的其他 modulemap 文件路径 -fmodule-map-file={modulemap_path} HEADER_SEARCH_PATHS:头文件搜索路径,可用于配置源码中引用的其他 Library 的头文件 OTHER_LDFLAGS:依赖其他二进制的编译依赖选项 SWIFT_INCLUDE_PATHS:swiftmodule 搜索路径,可用于配置依赖的其他 swiftmodule OTHER_SWIFT_FLAGS:Swift 编译选项,可配置依赖的其他 modulemap 文件路径 -Xcc -fmodule-map-file={modulemap_path}

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

推荐阅读更多精彩内容