首页 > 代码库 > Using Swift with Cocoa and Objective-C--在同个project中使用Swift和在同个project中

Using Swift with Cocoa and Objective-C--在同个project中使用Swift和在同个project中

http://www.cocoachina.com/newbie/basic/2014/0605/8688.html


技术分享
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
  1. #import "XYZCustomCell.h" 
  2. #import "XYZCustomView.h" 
  3. #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
  1. let myCell = XYZCustomCell() 
  2. 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
  1.   
  2. #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
  1. #import <XYZ/XYZCustomCell.h> 
  2. #import <XYZ/XYZCustomView.h> 
  3. #import <XYZ/XYZCustomViewController.h> 
 
Swift 将会看到全部你在  umbrella header  中公开暴露出来的头文件,框架 target 中的全部 Swift 文件都能够訪问你 Objc 文件的内容,不须要不论什么 import 语句。

SWIFT
  1. let myCell = XYZCustomCell() 
  2. 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
  1. #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
  1.   
  2. import FrameworkName 
 
用以下的语法将框架导入到不同 target 的 Objc .m 文件里:
OBJECTIVE-C
  1.   
  2. @import FrameworkName; 
 
在Objective-C中使用 Swift

当你将 Swift 代码导入 Objc 文件之后,用普通的 Objc 语法使用 Swift 类。
OBJECTIVE-C
  1.   
  2. MySwiftClass *swiftObject = [[MySwiftClass alloc] init]; 
  3. [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
  1. // MyObjcClass.h 
  2.   
  3. @class MySwiftClass; 
  4.   
  5. @interface MyObjcClass : NSObject 
  6. - (MySwiftClass *)returnSwiftObject; 
  7. /* ... */ 
  8. @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 代码。

Using Swift with Cocoa and Objective-C--在同个project中使用Swift和在同个project中