Objective-C与Swift相互调用

2017-5-5

不同的语言之间通常可以互相调用,一个工程使用不同的语言来编写也是经常有的情况。

运行时(runtime),就是代码运行的环境,一个语言可能会使用FFI(Foreign Function Interface)来与其他语言进行通讯,与其他情况不一样的是,Swift是包含OC的运行时的,所以Swift与OC之间的混编会方便很多。

Objective-C中调用Swift

建立一个mac的工程,如下所示:

在这个位置新建一个Swift文件,这是系统会提示询问是否要要自动创建bridging header,这个文件是swift调用oc的代码时需要用到的,为了演示,我们选择不自动创建,后面再手动创建:

现在目录如下所示:

编写swift代码:

import Foundation

public class SwiftCode: NSObject {
    @objc public func testSwiftCode() {
        print("testSwiftCode")
    }
}

这里需要注意的是:

我们可以查看swift Interface文件来看我们的swift文件对外暴露了哪些方法和类,这个文件的并不真实存在,作用类似与c和oc的.h文件,swift中只是为了我们方便看。

要想让OC能调用Swift的代码,需要在OC中导入一个xxx-Swift.h文件,这个文件系统已经帮我们自动生成了,查看这个文件的方法如下:

在这个文件的最下面,我们可以看到:

我们编写OC代码:

#import "AppDelegate.h"
#import "OC_Swift_Interoperability-Swift.h"

@interface AppDelegate ()

@property (strong) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    SwiftCode *swiftcode = [[SwiftCode alloc] init];
    [swiftcode testSwiftCode];
}

@end

现在运行程序,就可以看到控制台输出:testSwiftCode

Swift返回结构体给Objective-C

如果一个Swift的方法返回类型为结构体,这个方法是不能在前面加@objc的,Swift的结构体不能直接返回给OC,这个时候我们可以新建一个Swift类,这个类相当于对要使用的结构体包一层,各个方法返回结构体对应的成员,具体做法可以见:How to use Swift struct in Objective-C

Swift中调用Objective-C

Bridging Header的方式

建立一个oc的类用于测试,如下:

建立一个头文件,名字为xxx-Bridging-Header.h这个头文件的内容就是import你想要在Swift中使用的Objective-C类,这里的情况,头文件名字为OC-Swift-Interoperability-Bridging-Header.h,内容如下:

在Build Settings中,在Swift Compiler - General中,设置Objective-C Bridging Header为刚刚建立的头文件

注意这里为头文件在项目中的绝对地址(跟info.pllist的设置一样),如项目文件夹为aaa,头文件在项目根目录,那么就设置为aaa/xxx-Bridging-Header.h。这里的情况如下:

设置好后build一下就可以直接在Swift中使用Objective-C的类了,修改SwiftCode.swift的代码,以及运行结果如下:

.modulemap的方式

modules 是一种更好用的代码库形式,原本的 #include 来导入一个库有一些不足的地方,modules 更好的解决了一些问题,关于modules的详细说明可以看看llvm关于modules的官方文档

具体的modulemap的方式实现swift调用oc代码,可以看这篇文章就好,已经很简洁明了。

参考

Swift and Objective-C in the Same Project

Understanding Objective-C and Swift interoperability

用.modulemap实现模块化