一.swiftmodule目录文件
我们知道 oc调用swift 以及swift调用oc的流程如下
但是我们创建swiftframework的时候 那么我就会有下面的一些疑问
- 1.swift没有头文件,只有.swiftmodule
- 2.swift Framework不能使用 .Bridging-Header.h
- 3.swift涉及到的编译参数
- swift没有头文件的概念,那么我们外界要是使用siwift中的public修饰的类和函数该怎么办?
- swift库中引入了一个全新的文件.swiftmodule
1.用swift语言编译生成的framework的目录结构 我们都知道swift是没有头文件的 而swiftmodule里面相当于就是头文件
文件包含如下
- .swiftmodule 包含序列化过的AST(抽象语法树),(Abstract Syntax Tree) 也包含SIL(swift中间语言,Swift Intermediate Language)
- .swiftdoc: 用户文档
我们研究一下 x86_64-apple-macos.swiftmodule 这里面包含我们声明的结构体的信息
需要用到Swift REPL: swift解释器 永来运行调试Swift代码
1.swift -> repl -> swiftmodule
xcrun -show-sdk-path
-frontend:使用Swift前端工具
-repl:进入解释器
-sdk:环境使用的SDK
-F:framework所在的路径
-I:library所在的路径
:print_module :打印module声
/Volumes/Tino/swift-source/build/Ninja-RelWithDebInfoAssert+stdlib-DebugAssert/swift-macosx-x86_64/bin/swift -frontend -repl -sdk /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -F /Users/Desktop/Swift/Swift混编/Framework/Products
显示.swiftmodule里面的内容
二.Module Stability
Module Stability 是解决模块间编译器版本兼容的问题 这意味着使用不同版本编译器构建的Swift模块可以在同一个应用程序中一起使用
三.Library Evolution
从swift5开始,库能够声明稳定的ABI,允许库二进制文件替换为更新版本,而无需重新编译客户端程序
举个例子 在framework里面声明变量age = 2
直接运行 相当于编译framework 同时运行demo
当我们恢复name字段 只编译framework
运行如下 Run Without Building 运行已经编译好的产物 不重新编译
得到结果如下
为什么打印的age的值是1 为什么打印的是name的值 是因为swift是静态语言 编译的时候已经确定了内存结构 按内存结构找到了第一个就是name的值 怎么解决呢 看下面截图
我们设置一个BUILD_LIBRARY_FOR_DISTRIBUTION = YES 在按上面的流程操作一下 得到正确结果
相当于给代码推到runtime时 这样会导致性能下降 这个时候我们就会有个关键字@frozen 添加这个字段就是不推到运行时 不添加的话就推到运行时 拿上面的例子举例 如果添加这个关键字得到的结果age = 1 代表上面结论就正确了
1.全部运行
2.编译framework 运行 Run Without Building
这个关键字的应用场景 我的库swift组件1.0 -》 升级到2.0 我的app代码功能不需要重新编译就可以了
四.xcconfig编写指南
1.我们先添加一个脚本
- 第一步删除Products下生成的Framework
- 第二步从BUILT_PRODUCTS_DIR(framework产物所在的目录)拷贝到 Products
Xcode -> shell -> clang/swiftc ->build setting 在界面可以设置
build setting 里面没有设置的参数 相当于给shell变量添加参数 或者在build setting里面设置比较麻烦 我们可以通过配置Config文件去配置build setting里面的参数
1.先创建一个Config文件
2.文件里面包含一个介绍参数配置的地址 help.apple.com/xcode/#/dev…
3.这个config文件如何生效 在这里面设置 对应Debug 和 release 分别设置
4.例子(一)
我们设置一下 Other Linker Flags
在config里面添加配置 以Declaration为key
在 Other Linker Flags 就会显示
5.例子(二)
如果手动配置 先改为这个 发现和 config里面就不显示
在里面配置添加$(inherited) config里面的配置继承过来就会显示
6.例子(三)
添加config2
在config 里面引入 config2
在build setting 里面不显示
通过脚本打印参数
发现都有加入
7.例子(四)
如果在debug 和release 都设置config
但是config只在Debug下生效
显示结果release下不显示
五.module(管理一组头文件)
1.我们先创建一个module.modulemap文件 倒入LGTest.h
2.找到设置module.modulemap文件的key
3.通过config文件 导入module.modulemap
4.编译 报错
5.因为LGTest.h 里面倒入了Foundation
6.需要在module.module.map里面添加 export Foundation 或者 export * 编译成功
7.我们不能这么倒入 因为framework专属 编译报错
8.如果我们倒入多个文件不可能写一堆header 这个时候就用到了 umbrella 这个关键字管理一组文件
9.在 LGTest-Header-Umbrella.h文件 通过一个伞头文件 映射到其它多个文件
10.如果我们把module 变成 framework module 编译报错 找不到伞头文件
11.因为framework 的文件结构是 Header+.a+签名+资源文件+Modules 头文件放到Headers文件夹里面 我们试一下 编译成功
12.如果我们添加头文件的方式改为framework的方式添加
13.如果我们想已这种方式引入头文件 在module.modulemap文件声明子module就OK了
14.把伞文件里面的文件导出编译也是OK的
15.添加explicit 只有添加显示的子module才会添加 子模块
16.requires objc 使用子module源码文件必须是一个OC文件
1.错误
2.正确