Swift系列文章由CocoaChina翻译小组翻译自苹果的官方文档:Using
Swift with Cocoa and Objective-C--Swift and Objective-C in the Same Project。本篇译者:haolloyin(github主页),敬请勘误。
Swift与Objective-C的兼容能力同意你在同一个project中同一时候使用两种语言。你能够用这样的叫做“mix and match”的特性来开发基于混合语言的应用。使用Swfit的最新特性--“mix and match”。你能够实现应用的一部分功能,并无缝地并入已有的Objective-C的代码中。
Mix and Match 概述
Swift与Objective-C文件能够在一个project中并存,无论这个project原本是基于Objective-C还是Swift。
你能够直接往现有project中简单地加入还有一种语言的文件。这样的自然的工作流使得创建混合语言的应用或framework target,与用单独一种语言时一样简单。
编写混合语言的工作流程仅仅有一点点差别。这取决于你是在写应用还是写框架。以下描写叙述了用两种语言在一个target中导入模型的情况,兴许章节会有很多其它细节。
在同一个App Target中进行代码导入
假设你在写混合语言的应用,可能须要用Swift代码訪问Objective-C代码。或者反之。本章描写叙述的流程适用于non-framework target。
将Objective-C导入Swift
要在同一个app target中导入Objective-C文件供Swift使用,你须要依赖Objective-C的桥接头文件(Objective-C bridging header)来暴露给 Swift。当你加入 Swift 文件到现有的Objective-C应用时,Xcode 会自己主动创建这些头文件,反之亦然。
假设你允许,Xcode 会在源文件创建的同一时候生成头文件,并用product的模块名加上 -Bridging-Header.h命名。关于 product 的模块名,详见 Naming Your Product Module。
你应该编辑这个头文件来对Swift暴露出Objective-C代码。
To import Objective-C code into Swift from the same target
1.在Objective-C桥接头文件里,导入不论什么你想暴露给 Swift 的头文件。比如:
OBJECTIVE-C
- #import "XYZCustomCell.h"
- #import "XYZCustomView.h"
- #import "XYZCustomViewController.h"
2.在Build Settings中,确保Objective-C桥接头文件的build setting是基于 Swfit 编译器,即Code Generation 含有头文件的路径。
这个路径必须是头文件自身的路径。而不是它所在的文件夹。
这个路径应该是你project的相对路径,类似 Info.plist 在 Build Settings 中指定的路径。在大多数情况下,你不须要改动这个设置。
在这个桥接头文件里列出的全部公开的Objective-C 头文件都会对 Swift 可见。
之后当前 target 的全部 Swift 文件都能够使用这些头文件里的方法,不须要不论什么import语句。
用 Swift 语法使用这些Objective-C代码,就像使用系统自带的类一样。
SWIFT
- let myCell = XYZCustomCell()
- myCell.subtitle = "A custom cell"
将 Swift 导入Objective-C
向Objective-C中导入Swift代码时,你依赖 Xcode 生成的头文件来向Objective-C暴露 Swift 代码。这个自己主动生成Objective-C头文件,声明了target 中全部 Swift 代码中定义的接口。能够把这个Objective-C头文件看作 Swift 代码的umbrella header。
它以 product 模块名加 -Swift.h 来命名。关于 product 的模块名,详见 Naming Your
Product Module。
你不须要做不论什么事情来生成这个头文件。仅仅须要将它导入到你的Objective-C代码来使用它。注意这个头文件里的 Swift 接口包括了它所使用到的全部 Objc 类型。
假设你在 Swift 代码中使用你自己的Objective-C类型,确保先将相应的 Objc 头文件导入到你的 Swift 代码中,然后才将 Swift 自己主动生成的头文件导入到 Objc .m 源文件里来訪问 Swift 代码。
To import Swift code into Objective-C from the same target
在同样 target 的 Objc .m 源文件里。用以下的语法来导入Swift 代码:
OBJECTIVE-C
-
- #import “ProductModuleName-Swift.h”
target 中不论什么 Swift 文件将会对 Objc .m 文件可见,包含这个 import 语句。
关于在 Objc 代码中使用 Swift 代码。详见 Using Swift from Objective-C。
在同个Framework Target中导入代码
假设你在写一个混合语言的框架,可能会从 Swift 代码訪问 Objc 代码。或者反之。
将 Objc 导入 Swift
要将一些 Objc 文件导入到同个框架 target 的 Swift 代码中去。你须要将这些文件导入到 Objc 的 umbrella header 来供框架使用。
To import Objective-C code into Swift from the same framework
确保将框架 target 的 Build Settings > Packaging > Defines Module 设置为 Yes 。然后在你的 umbrella header 头文件里导入你想暴露给 Swift 訪问的 Objc 头文件,比如:
OBJECTIVE-C
- #import <XYZ/XYZCustomCell.h>
- #import <XYZ/XYZCustomView.h>
- #import <XYZ/XYZCustomViewController.h>
Swift 将会看到全部你在 umbrella header 中公开暴露出来的头文件,框架 target 中的全部 Swift 文件都能够訪问你 Objc 文件的内容,不须要不论什么 import 语句。
SWIFT
- let myCell = XYZCustomCell()
- myCell.subtitle = "A custom cell"
将 Swift 导入 Objc
要将一些 Swift 文件导入到同个框架的 target 的 Objc 代码去,你不须要导入不论什么东西到umbrella header文件,而是将 Xcode 为你的Swift代码自己主动生成的头文件导入到你的 Obj .m 源文件去。以便在 Objc 代码中訪问 Swift 代码。
To import Swift code into Objective-C from the same framework
1.确保将框架target 的 Build Settings > Packaging 中的 Defines Module 设置为 Yes 。用以下的语法将 Swift 代码导入到同个框架 target 下的 Objc .m 源文件去。
OBJECTIVE-C
- #import <ProductName/ProductModuleName-Swift.h>
这个 import 语句所包括的 Swift 文件都能够被同个框架 target 下的 Objc .m 源文件訪问。关于在 Objc 代码中使用 Swift 代码。详见 Using Swift from Objective-C。
导入外部 Framework
你能够导入外部框架,无论这个框架是纯 Objc,纯 Swift。还是混合语言的。
import 外部框架的流程都是一样的,无论这个框架是用一种语言写的,还是包括两种语言。
当你导入外部框架时,确保 Build Setting > Pakaging > Defines Module 设置为 Yes 。
用以下的语法将框架导入到不同 target 的 Swift 文件里:
SWIFT
-
- import FrameworkName
用以下的语法将框架导入到不同 target 的 Objc .m 文件里:
OBJECTIVE-C
-
- @import FrameworkName;
在Objective-C中使用 Swift
当你将 Swift 代码导入 Objc 文件之后,用普通的 Objc 语法使用 Swift 类。
OBJECTIVE-C
-
- MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
- [swiftObject swiftMethod];
Swift 的类或协议必须用 @objc attribute 来标记。以便在 Objc 中可訪问。
这个 attribute 告诉编译器这个 Swift 代码能够从 Objc 代码中訪问。假设你的 Swift 类是 Objc 类的子类,编译器会自己主动为你加入 @objc attribute 。
详见 Swift Type Compatibility。
你能够訪问 Swift 类或协议中用 @objc attribute 标记过东西,仅仅要它和 Objc 兼容。
不包含一下这些 Swift 独有的特性:
Generics - 范型
Tuples - 元组
Enumerations defined in Swift - Swift 中定义的枚举
Structures defined in Swift - Swift 中定义的结构体
Top-level functions defined in Swift - Swift Swift 中定义的顶层函数
Global variables defined in Swift - Swift 中定义的全局变量
Typealiases defined in Swift - Swift 中定义的类型别名
Swift-style variadics
Nested types - 嵌套类型
Curried functions - 柯里化后的函数
比如带有范型类型作为參数,或者返回元组的方法不能在Objective-C中使用。
为了避免循环引用,不要将 Swift 代码导入到Objective-C头文件里。可是你能够在Objective-C头文件里前向声明( forward declare )一个 Swift 类来使用它。然而。注意不能在Objective-C中继承一个 Swift 类。
To reference a Swift class in an Objective-C header file
这样前向声明 Swift 类:
OBJECTIVE-C
-
-
- @class MySwiftClass;
-
- @interface MyObjcClass : NSObject
- - (MySwiftClass *)returnSwiftObject;
-
- @end
Product Module命名
Xcode 为 Swift 代码生成的头文件的名称。以及 Xcode 创建的 Objc 桥接头文件名,都是从你的 product 模块名生成的。默认你的 product 模块名和 product 名一样。然而,假设你的 product 名有特殊字符(nonalphanumeric,非数字、字母的字符)。比如点号,那么它们会被下划线( _ )替换之后作为你的 product 模块名。假设 product 名以数字开头,那么第一个数字会用下划线替换掉。
你能够给 product 模块名提供一个自己定义的名称,Xcode 会用这个名称来命名桥接的和自己主动生成的头文件。你仅仅须要在改动在 build setting 中的 Product Module Name 就可以。
故障建议和提醒
?把 Swift 和 Objc 文件看作同样的代码集合,并注意命名冲突;
?假设你用框架,确保 Build Setting > Pakaging > Defines Module 设置为 Yes 。
?假设你使用 Objc 桥接头文件。确保在 Build Settings 中 Objc 桥接头文件的 build setting 是基于 Swfit 编译器,即 Code Generation 含有头文件的路径。这个路径必须是头文件自身的路径,而不是它所在的文件夹。
?Xcode 使用你的 product 模块名。而不是 target 名来命名 Objc 桥接头文件和为 Swift 自己主动生成的头文件。详见 Naming Your Product Module;
?为了在 Objc 中可用, Swift 类必须是 Objc 类的子类,或者用 @objc 标记;
?当你将 Swift 导入到 Objc 中时,记住 Objc 不会将 Swift 独有的特性翻译成 Objc 相应的特性。详见列表 Using Swift from Objective-C;
?假设你在 Swift 代码中使用你自己的 Objc 类型,确保先将相应的 Objc 头文件导入到你的 Swift 代码中。然后才将 Swift 自己主动生成的头文件 import 到 Objc .m 源文件里来訪问 Swift 代码。