iOS - 静态库、动态库从浅到深学习之路 (四)

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  

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值