随着swift ABI的稳定,越来越多的开发者开始使用swift语言开发项目,但是由于大部分工具库也还是使用OC写的,因此我们不得不需要在项目中采用swift与oc混编。

在开发app项目时,swift与oc混编其实很容易,xcode会自动为我们建立一个桥接文件,这样我们就很容易的在swift中调用oc的方法或类对象。

但是在开发framework的时候,xcode不会为我们建立这个桥接文件,因此我们在framework中也就不能采用桥接的方式进行混编了。

framework中实现混编的方式有两种:

第一种:也是最简单的一种,就是将oc的头文件暴露出来,并在framework的头文件中导入。(缺点:我们不想对外暴露的类或方法,不得不暴露出去)

这样一来,我们就可以在swift中直接引用oc的类了

第二种:配置modulemap,这个方法可以避免我们不得不对外暴露我们的oc类。

(1):在项目中创建module.modulemap文件,具体内容如下:

module MyObjcFramework {
header "oc/MyObjc.h" // 这里的路径是相对于module.modulemap的所在目录
export *
}

这里我们定义了一个MyObjcFramework的模块,也就是提供给swift导入的模块名称。

header是该模块的头文件,如果你需要了解关于module的更多详细信息,可以查看这篇文章,或者Clang Module's documentation

(2):配置Swift Compiler - Search Paths  Import Paths:

这里是为了告诉编译器,我们自定义的module所在路径,这里指定了项目的根目录:$(SRCROOT),当然你也可以指定的更具体,像下面这样:

然后我们就可以在swift中导入我们自定义的module,从而引用oc类。

import Foundation
import MyObjcFramework // 导入自定义模块 public func testPrint(_ str: String) {
let objc = MyObjc()
objc.printStr(str)
}

以上两种方法解决了我们在使用swift开发framework时与oc混编的问题,一般常用第二种方式,不过依具体情况决定。

另外说一下swift开发framework与OC的区别,使用swift开发framework导出的framework文件中的Modules目录下多出一个xxx.swiftmodule包,这个是swift提供的公共组件接口定义。

我们看一下这个包里都有哪些文件:

swiftdoc应该是api文档的描述。swiftmodule定义了MyKit组件的api公共接口。

Project里的文件如下:

另外当你在Build Settings中设置Build Libraries for Distribution = YES时,再次Build你的framework后,在xxx.swiftmodule包中会多出一个swiftinterface文件。

这个是swift5.1之后对swiftmodule的补充,它们的目的都是为了实现编译一个向后兼容的二进制库。

下面是重点,重点,重点。

在合并模拟器与真机的二进制库时,不能像OC那样简单的将合并后的二进制文件替换就可以了,因为swift中模块定义的公共接口都是在swiftmodule中定义的,而它们也是区分架构的,因此你需要将合并后的二进制文件替换之外,将不同架构的swiftmodule和swiftinterface文件拷贝到当前framework/Modules/xxx.swiftmodule包中。

当然还有另外一种合并多平台架构的方式,那就是xcframework,但是我却在这里遇到了一个问题,那就是在swift于OC混编时使用modulemap时生成的xcframework,导入到实际app工程时报错,下面是具体的错误:

MyHandler就是在swift编写的framework工程中利用module.modulemap对OC文件的一种引入方式,对应的modulemap如下:

module "MyHandler" {

    umbrella header "./src/oc/MyTextHandler.h"

    export *
module * { export * }
}

使用MyHandler的地方:

import UIKit
import DrFlexLayout_swift
import MyHandler public class MViewController: UIViewController { let text: String
let handler: MyTextHandler public init(text: String) {
self.text = text
self.handler = MyTextHandler(prefix: "T")
super.init(nibName: nil, bundle: nil)
}
}

framework的工程可以正常编译通过,但是在合并成xcframework后,将xcframework导入到app工程后编译就会包上面的错误。

这个问题我暂时没办法解决,希望知道的解决方法朋友在下面留言告诉我一下,不胜感激!

难道就不能使用xcframework了吗?当然是可以使用了,前面我们提到过在swift编写的framework中混编OC或c时,还有另一种方法,那就是将OC或c的头文件暴露在framework工程的头文件中,这样生成的xcframework就可以正常使用了,但是缺点自然是有的,这也是没办法的办法。

感谢@ronzheng的帮助,以上的问题已经得到解决。解决办法是将import MyHandler替换成@_implementationOnly import MyHandler即可。我遇到的这个问题也有其他人同样遇到了,可以看这里查看,关于@_implementationOnly的作用没有官方解释,不过我推测就是将被修饰的导入的模块私有化,在使用中我同样遇到了一些其他问题,在评论中有提到。因此在使用@_implementationOnly导入内部私有模块时,最好放在内部类中使用。

用swift开发framework时采用OC混编的解决方案的更多相关文章

  1. Swift数独游戏优化——C++与OC混编、plist自动生成

    一.为什么要C++与OC混编? 在我之前的数独游戏中涉及到的数独游戏生成算法是参考的网上其他人的算法,是利用C++来实现的.   但是在我的例子中我发现这样存在一定的局限性: 1.我是利用Termin ...

  2. iOS开发之swift与OC混编出现的坑,oc中不能对swift的代理进行调用,不能访问swift中的代理,swift中的回调方法

    1. Swift与oc混编译具体怎么实现,这儿我就不重复讲出了,网上有大把的人讲解. 2. 在swift与OC混编的编译环境下, oc类不能访问swift创建类中的代理? 解决方法如下: 在代理的头部 ...

  3. iOS8开发~Swift(五)Swift与OC混编

    一.概要 首先看<The Swift Programming Language>中提到"Swift's compatibility with Objective-C lets y ...

  4. Swift & OC 混编 浅析

    转载自:http://www.infoq.com/cn/articles/wangyi-cartoon-swift-mixed-practice?utm_campaign=rightbar_v2&am ...

  5. swift c++ oc 混编

    http://www.tuicool.com/articles/QZNrErM iOS 里面 Swift与Objective-C混编,Swift与C++混编的一些比较 时间 2015-03-23 23 ...

  6. Swift与OC混编

    OC调用Swift的方法:添加 import "xxxx-Swift.h" 头文件即可 Swift调用OC的方法:需要建立桥接: xxxx-Bridging-Header.h 头文 ...

  7. cocoapod Podfile use frameworks swift/oc混编 could not build module xxx

    前置: 知名的pod: AFNetworking 我自己的pod:  AFNetworking+RX  3.1.0.18 里面有一段代码是: #import <Foundation/Founda ...

  8. iOS 静态类库 打包 C,C++文件及和OC混编

    iOS 静态类库 编译 C,C++ 我们都知道,OC 原生支持C, 在 创建的 OC类的 .m 里面,可以直接编写C的代码: 同样 Xcode 也支持 OC ,C++的混编,此时,我们通常把OC创建的 ...

  9. iOS之 C++与oc混编

    声明:本文只是随笔,自己做个笔记方便以后查阅如要转载,注明出处.谢谢! 2016年第一篇随笔!!! 由于最近要搞一个项目用到c++的一些api所以要混编,于是就记录下这个过程中的一些细节上的东西! O ...

  10. swift和 oc 混编2-备

    在Swift语言出现之前,开发iOS或OS X应用主要使用Objective-C语言,此外还可以使用C和C++语言,但是UI部分只能使用Objective-C语言. 选择语言 Swift语言出现后,苹 ...

随机推荐

  1. MQ 消息队列 比较

    为什么需要消息队列 削峰 业务系统在超高并发场景中,由于后端服务来不及同步处理过多.过快的请求,可能导致请求堵塞,严重时可能由于高负荷拖垮Web服务器. 为了能支持最高峰流量,我们通常采取短平快的方式 ...

  2. 微机原理与系统设计笔记7 |常用芯片接口技术、中断系统与可编程中断控制器8259A

    打算整理汇编语言与接口微机这方面的学习记录.本部分介绍常用芯片接口技术.中断系统与可编程中断控制器8259A. 参考资料 西电<微机原理与系统设计>周佳社 西交<微机原理与接口技术& ...

  3. .Net 获取URL中指定参数值

    有时候我们调用第三方接口,返回的并不是完整的链接带参数,而我们只需要获取指定的一些参数 例如:code=200&msg=success&timestamp=1657539&no ...

  4. 2023年2月份CKA考试历程

    2023年2月份CKA 考试历程 目录 2023年2月份CKA 考试历程 一.购买CKA/CKS套餐 二.CKA 考试练习 三.CKA 第一次考试 考前考中 考后 四.CKA 第二次考试 五.考试的一 ...

  5. day09-MyBatis缓存

    MyBatis缓存 mybatis – MyBatis 3 | cache MyBatis 一级缓存全详解(一) MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制. 为了 ...

  6. JavaScript之this、let、const关键字

    各场景下的this this的意思:百度翻译为:这.这么.本 在JavaScript中,表示当前对象的引用关键字,没有特殊含义. 在一个方法中,this表示该方法所属的对象. 如果单独使用,this表 ...

  7. 2021-08-17:cocos creator 如何控制 spine 动画的进度

    // 传入spine与进度比例(注意初始要把spine的TimeScale设置为0)updateSpine(spine: sp.Skeleton,rate: number) { const track ...

  8. spring boot 配置多套数据源

    问题:需要在多个数据库中查询数据,不适用sql中的use语句. 导包 pom.xml <!-- mybatis,使用mybatis-plus也行,虽然plus的单表查询很强,在大部分情况下需要编 ...

  9. cuda+pytorch环境安装

    本机cuda版本为v11.5 conda install cudatoolkit 使用 CUDA 11.3版本的配置 conda install pytorch==1.11.0 torchvision ...

  10. Linux中使用Makefile来运行QuestaSim

    环境:Win7x64,VMware15.0,centOS7.0,QuestaSim10.7c 假设已经编辑好了一个全加器还有运行这个DUT的testbech,代码如下: 点击查看代码 // filen ...