Module(模块介绍)
一个Module是机器代码和数据的最小单位,可以独立于其他代码单位进行连接。
通常, Module是通过编译单个源文件生成的目标文件,例如,当前的test.m文件被编译成目标文件test.o时,当前的目标文件就是一个Module.
但是有一个问题,Moule在调用的时候会产生开销,比如我们在使用一个静态库的时候。
include : 有重复编译相同文件的问题
import : 引入了Module,相同的代码只编译一次, 提升了编译速度。
Moule :默认xcode是开启的,无论代码里面写 include 或者import都会被转化为 @import * 方式。
下面是AFNetworking的 module 文件。
// framework module 名称 AFNetworking
framework module AFNetworking {
// umbrella <目录> 伞柄 <目录>/.h
// AFNetworking-umbrella.h 伞柄 AFNetworking-umbrella.h/.h 伞骨
umbrella header "AFNetworking-umbrella.h"
// 重新导出
export *
// module: 子module*
module * { export * }
}
实操:
1. 自己创建一个 Framework ,里面实现一个dog类和一个cat类,创建一个头文件 zgrheader.h, 包含下dog与cat类。
2. 直接从工程里面去拖这个文件格式,然后去改,创建一个Modulemap ,代码如下 ,拖放到我们的framework下,必须拷贝进去。
framework module zgrFramework {
umbrella header "zgrheader.h"
export *
// 子module
explicit module cat {
header "cat.h"
export *
}
// 显示申明 explicit
explicit module dog {
header "dog.h"
export *
}
}
3. 配置下module的路径,在 build setting下,搜索module,把路径设置进去。
4. 这样我们就可以在自己的工程中,通过import <zgrFramework/cat.h>来引入framework指定的类。
swift中 module使用。
private_module
对外界告诉我这个framework ,这些类是私有的的文件,你想使用和普通的Module使用是一样的。 使用 private_module, 文件名格式 : 文件名.private.modulemap
类的头部写法格式 : framework module 文件名_Private { }
私有的module也需要在build Setting里面设置private module的文件目录。
Swift静态库的合并。
xcode9后, swift支持静态库。
swift没有头文件的概念,外界需要使用swift中的public修饰的类和函数怎么办?
引入了 .swiftmodule. 文件
.swiftmodule包含序列化过的AST抽象语法书 , Abstract syntax tree , 也包含SIL (swift中间语言)
推荐使用libtool,两个静态库合并成另外一个静态库命令:
libtool -static SwiftA SwiftB -o libSwiftC.a
xcconfig配置
HEADER_SEARCH_PATHS = $(inherited) '${SRCROOT}/Public/LGSwiftA.framework/Headers' '${SRCROOT}/Public/LGSwiftB.framework/Headers'
// OTHER_CFLAGS:传递给用来编译C或者OC的编译器,当前就是clang
// -fmodule-map-file: 要加载的module map文件路径
OTHER_CFLAGS = $(inherited) '-fmodule-map-file=${SRCROOT}/Public/LGSwiftA.framework/module.modulemap' '-fmodule-map-file=${SRCROOT}/Public/LGSwiftB.framework/module.modulemap'
// SWIFT_INCLUDE_PATHS: 传递给SwiftC编译器,告诉他去下面的路径中查找module
SWIFT_INCLUDE_PATHS = $(inherited) '${SRCROOT}/Public/LGSwiftA.framework' '${SRCROOT}/Public/LGSwiftB.framework'
APInotes
API 注解提供了一种机制,使得 Objective-C 的 API 可以添加额外的语义信息,但不必写在框架 API 的头文件中。在导入这些框架时,相应的语义信息可以被 Swift 的编译器直接使用,从而可以将框架的 API 更好的应用在 Swift 中。
API 注解由一系列的 .apinotes
文件组成,每个 .apinotes
文件都包含单个 Objective-C 模块的注解,该注解是使用 YAML
写的,参见 Clang 库。当 Swift 导入这些模块时,Swift 的编译器只是简单的加载这些 YAML
文件。
为尚未有注解文件的系统模块添加一个注解文件时,需要创建一个以模块名称为文件名,以 .apinotes
为文件后缀的文件,写入信息后,更新 CMakeLists.txt 文件,而后,更新的 API 注解则会在下一次系统编译时显示。
例如:
---
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
# https://clang.llvm.org/docs/APINotes.html
总结:
1. module -> 头文件 -> 目标文件的关系
2. modulemap -> 头文件 -> 目标文件的映射
3. module: 定义一个module
export: 导出当前代表的头文件使用的头文件
export * : 匹配目录下所有的头文件
module * : 目录下所有的头文件都当做一个子module
explicit : 显示申明一个module的名称
4. swift库使用oc代码: 不能使用桥接文件方法
1. oc的头文件放到modulemap下
2. oc的头文件放到私有的modulemap下
3. 协议的方式 投机取巧
5. swift的静态库合并
难点: .swiftmodule 文件 (swift的头文件)
1. libtool 合并静态库本身
2. 用到的头文件和swift头文件和modulemap文件通过目录的形式放到一起
3. oc要用合并的静态库: clang: other c flags : -fmoudule-map-file <modulemap path>
4. swift要合并的静态库 : swiftC: other swift flags 显示告诉swiftC <Moudule dir>
6. OC映射到swift方式
1. 宏
2. <工程名称>.APInotes