Objective-C引入Swift代码
OC与Swift混编项目中,如何在Objective-C代码中访问Swift的类型与声明?
概述
一般来讲,通过在Objective--C中导入Xcode生成的头文件(Xcode-generated header file)可以引用Swift中声明的类型。这个文件是一个Objective-C类型的头文件,其中包含了swift声明的接口,你可以认为这是一个swift对外暴露的头文件。而且这个Xcode生成的头文件(Xcode-generated header file)无需开发者做任何额外的事情,只是简单的导入到Objective-C中使用即可。
这个Xcode生成的头文件是以工程模块名称加上"-Swift.h"为后缀所构成。默认情况下工程模块名称就是工程的名称,需要注意两点:
- 名称中的非字母数字字符用下划线"_"代替。
-
以数字开头的工程名称,第一个数字被替换为下划线 "_" 。
需要注意的是,Objective-C中引用Swift代码的操作会略有不同,具体取决于是在应用程序中导入引用还是在framwork中引用。
应用程序中导入
在应用程序中可以使用如下方法将Swift代码引入到Objective-C代码中:
#import "ProductModuleName-Swift.h"
默认情况下Xcode生成的头文件会包含Swift中以public或者open修饰的接口。假如程序中已经包含Objective-C桥接头文件,那么Xcode生成的头文件同样会包含以internal修饰的接口。使用private或者fileprivate修饰的方法则不会在Xcode生成的头文件中,并且不会暴露给Objective-C运行时,除非是通过@IBAction,@IBOutlet,@objc修饰的属性。单元测试代码中,可以访问internal修饰的声明,和用@testable加前缀是一样的效果。
需要注意的是,Xcode生成的头文件中swift包含了所有引用到的Objective-C类型,所以需要首先导入包含这些类型的Objective-C头文件。
最后,Xcode生成的头文件的工程模块名称是可以自定义的。具体方法是
Build Settings -> Objective-C Generated Interface Header Name
Framework中导入
有时你在编写一个Framework的时候也会出现OC和Swift混编的情况。在framwork开发中同样需要将Xcode生成的头文件导入到 ".m" 。
因为Xcode生成的头文件是framwork的publick接口一部分,所以只有被public或open修饰符修饰的声明才会被包含。使用internal修饰符标记并继承于Objective-C类中的方法和属性可以被Objective-C的runtime访问。然而,它们并不能在编译期访问以及不会出现在Xcode生成的头文件中。
在同一个框架中将Swift代码导入Objective-C方法:
- Build Settings -> Packaging -> Definies Module => Yes
- 在同一个garget中将Swift代码通过如下方法导入Objective-C .m文件
#import <ProductName/ProductModuleName-Swift.h>
在Objective-C头文件中前置声明Swift对象
在同一个target中,Objective-C头文件引用Swift中的类或协议会导致循环引用发生,为了避免产生这个问题,可以通过前置声明解决,实例代码如下:
// MyObjcClass.h
@class MySwiftClass;
@protocol MySwiftProtocol;
@interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
@end
swift中类和协议仅可在方法和属性类型中做前置声明。
总结回顾
