在Swift中能够直接使用Objective-C语言提供的api (包括系统框架与自己的定制代码),也能够在Objective-C中使用Swift提供的类和api ,还能够在一个工程中同时混合使用Swift
和Objective-C两种语言,两种语言之间能够互通和互用。
任意Objective-C的框架或C库(包括所有的Objective-C系统框架,例如Foundation、UIKit、SpriteKit以及系统提供的公共c库)作为模块被直接导入Swift 供Swift语言使用。
例如为了使用Foundation框架,只需简单的在要使用Foundation框架的Swift文件的顶部添加一个如下的输入声明语句:
import Foundation
这样Foundation 框架包含的所有api包括NSDate、NSURL、NSMutableData以及所有的方法、属性和类别都能被该Swift文件直接使用。
一 、与Objective-C 语言和框架的集成
1.1 对象的实例化
为了在 Swift 中使用某个Objective-C 类,可以使用Swift语法调用它的某个初始化方法进行实例化。
UITableView *myTableView
= [[UITableViewalloc]initWithFrame:CGRectZerostyle:UITableViewStyleGrouped];
以上的一个Objective-C 对象的初始化方法在Swift语言中需要这样调用。
let myTableView:UITableView
=UITableView(frame:CGRectZero,style:
.Grouped)
由于Swift语言自动处理一个实例的内存分配,因此在Swift语言中不需要使用alloc进行内存分配。Objective-C 语言中作为实例初始化方法名字指示的init或 initWith前缀在Swift的初始化语法中也不需要,而用类的名字作为实例初始化方法的名字,跟着Objective-C 语言实例初始化方法名字initWith后面的单词作为Swift的初始化方法的第一个参数使用。
在Swift语言中,实例的初始化语法中对象的类型也可以省掉(如上例的UITableView),Swift可以自动正确地推断其类型,如下所示:
let myTableView=UITableView(frame:CGRectZero,style:
.Grouped)
为了一致和简化,Objective-C 的工厂方法在导入Swift时被自动映射为Swift语言的便利初始化方法。例如在Objective-C中如下调用一个工厂方法。
UIColor *color
= [UIColorcolorWithRed:0.5green:0.0blue:0.5alpha:1.0];
在Swift语言中,应该这样调用:
let color
=UIColor(red:0.5,green:0.0,blue:0.5,alpha:1.0)
1.2 属性和方法的存取
在Swift中使用点语法来存取和设置Objective-C 对象的属性和调用方法。
对于属性的存取在Swift中利用点语法直接使用属性的名字来存取该属性,如:
myTextField.textColor =
UIColor.darkGrayColor()myTextField.text =
"Hello world"
对于方法,Objective-C方法名字的第一部分在Swift中直接作为方法名,其余作为Swift方法的参数包括在方法的圆括号中。例如下面的一个Objective-C 方法。
[myTableViewinsertSubview:mySubviewatIndex:2];
在Swift中如下调用。
myTableView.insertSubview(mySubview,atIndex:2)
在Objective-C中的id类型 在导入Swift时被映射为Swift语言的AnyObject类型。
在Objective-C中的指针在导入Swift时被映射为Swift语言的optional类型。
1.3 扩展功能
能够使用扩展为Objective-C语言中已定义的类、结构和枚举(包括系统框架中或自己定义的)添加和扩展功能。
如使用扩展来添加属性(包括类和静态属性),扩展的属性必须是计算属性。如下所示使用扩展为CGRect类添加了一个计算属性area:
extension CGRect {
var area:CGFloat
{return width
*height}
}
let rect =CGRect(x:0.0,y:0.0,width:10.0,height:50.0)
let area =rect.area
// area: CGFloat = 500.0
也能使用扩展来为Objective-C语言的类添加协议的支持,如果协议是Swift定义的,你能为任意的结构或枚举类型(无论是Objective-C定义的还是Swift定义的)添加对该协议的支持。
但不能使用扩展来重写Objective-C 类型的属性或方法。
1.4 块与闭合
Objective-C中的块以Swift中的闭合方式导入Swift。
void (^completionBlock)(NSData
*, NSError *) = ^(NSData *data,NSError
*error) {/* ... */}
上面 Objective-C语言定义的块在导入Swift后需要这样使用(转换为闭合):
let completionBlock:
(NSData,NSError) ->Void
= {data,errorin/*
... */}
由于 Swift中的闭合和 Objective-C中的块是兼容的,因此你能够传递闭合(包括Swift的函数)给任何使用块作为参数的Objective-C方法。
1.5 对 Objective-C类的继承和使用Objective-C中的协议
在Swift 语言中,能定义一个继承自一个Objective-C类的Swift 类,也能在Swift 中直接使用Objective-C语言定义的协议。如下定义了一个派生自Objective-C框架UIKit中UIViewController类的一个Swift
子类。
import UIKit
class MySwiftViewController:UIViewController
{// define the class
}
如下定义了一个采用Objective-C中的UITableViewDelegate和UITableViewDataSource协议的Swift
类MySwiftViewController。
class MySwiftViewController:UIViewController,UITableViewDelegate,UITableViewDataSource
{// define the class
}
对于 Swift 定义的类(包括从Objective-C继承的类)总是使用Swift语言的初始化方法进行类的初始化,Swift自动转换Objective-C 的初始化方法为Swift中的初始化方法。
1.6 与Objective-C的兼容
当定义一个Swift类派生自NSObject或其它的Objective-C类时,Swift类自动与Objective-C兼容,Objective-C代码可以直接使用它。
注意在Objective-C中不能定义一个继承Swift类的子类。
如果Swift类不派生自Objective-C类,则Objective-C代码不能直接使用它,如果要使该Swift类能够被Objective-C代码使用,需要使用@objc
来标识它。
当在Objective-C代码中使用一个Swift API 时,编译器自动执行一个直接转换操作。Swift 的API 被转换为Objective-C的形式。
如Swift 中的一个函数func playSong(name: String)被转换为Objective-C语言的如下形式- (void)playSong:(NSString *)name。
Swift 的一个初始化方法init (songName: String, artist: String)被转换为Objective-C语言的如下形式:
- (instancetype)initWithSongName:(NSString *)songName artist:(NSString *)artist。
在 Swift中,也能使用@objc对类、属性、方法规定一个能够被Objective-C语言识别和使用的另外的名字。如下所示:
@objc(Squirrel)
class Белка {
@objc(initWithName:)
init (имя:String)
{/*...*/ }@objc(hideNuts:inTree:)
func прячьОрехи(Int,вДереве:Дерево)
{/*...*/ }}
1.7、 与Cocoa数据类型的桥接
Swift能够自动在一些Objective-C 和Swift类型之间相互转换,另外也有一些类型,能够在Swift和Objective-C 之间相互替换使用。可转换或可替换的类型被称作可桥接类型。如Swift 语言中的Array类型和Objective-C
中的NSArray类,Swift 中的String类型与Objective-C 中的NSString类,Swift 的Dictionary类型与Objective-C 中的NSDictionary类,都是可桥接类型。在Swift中,使用NSString的任何地方都能用String代替,并能同时使用两种类型提供的功能,如可以在Swift的String类型上调用NSString提供的capitalizedString方法。
为了在Swift中允许和使用桥功能,只需输入Foundation框架。如下所示:
import Foundation
let greeting
="hello, world!"let capitalizedGreeting
=greeting.capitalizedString// capitalizedGreeting: String = Hello, World!
还能够像创建String一样创建一个NSString对象,如下所示创建了一个NSString类型的对象:
import Foundation
let myString:NSString
="123"if let integerValue
= (myStringasString).toInt()
{println("\(myString)
is the integer \(integerValue)")}
Swift也自动在Int、Float、UInt、Double、Bool类型与NSNumber类型之间实现类型的桥接,因此可以使用Int、Float、UInt、Double、Bool类型来创建一个NSNumber对象。在需要的NSNumber类型参数的地方也可以传送一个Int、Float、UInt、Double、Bool类型的参数。
let n =42
let m:NSNumber
=n
注: Cocoa 的NSNumber类型与NSUInteger类型都被桥接为Swift的Int类型。
当从一个NSArray对象桥接为一个Swift Array数组时,NSArray数组的类型需要与AnyObject兼容,结果数组的类型为AnyObject[]。由于所有的Objective-C对象与AnyObject类型兼容,因此任何类型的NSArray对象都能被桥接为Swift数组。
同样,如果Swift数组中的元素与AnyObject兼容,一个Swift数组也能桥接为NSArray对象,否则将会出运行时错误。
同样也能像创建一个Swift数组一样创建一个NSArray对象。
let schoolSupplies:NSArray
= ["Pencil","Eraser","Notebook"]// schoolSupplies is an NSArray object containing NSString objects
二、与 C API的交互
2.1、 C语言基本类型
Swift提供了与C语言基本类型对等的类型。但除非特别需要,不推荐使用。
C Type Swift Type
bool CBool
char,
signed char
CCharunsigned char
CUnsignedCharshort
CShortunsigned short
CUnsignedShortint
CIntunsigned int
CUnsignedIntlong
CLongunsigned long
CUnsignedLonglong long
CLongLongunsigned long long
CUnsignedLongLongwchar_t
CWideCharchar16_t
CChar16char32_t
CChar32float
CFloatdouble
CDouble
2.2 C-style类型的枚举
在Objective-C 语言中用NS_ENUM宏标记的C-style类型的枚举或用NS_OPTIONS标记的选项在导入Swift时被自动转换为Swift形式的枚举。
OBJECTIVE-C
typedef NS_ENUM(NSInteger,UITableViewCellStyle)
{UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
被转换为如下的Swift枚举形式。
SWIFT
enumUITableViewCellStyle:Int
{caseDefault
caseValue1
caseValue2
caseSubtitle
}
2.3 指针
Swift避免直接使用指针,可是当需要时也提供了几种类型的指针供直接存取内存使用。
对于作为参数的指针,有如下映射关系:
C Syntax Swift Syntax
const void * CConstVoidPointer
void * CMutableVoidPointer
const Type * CConstPointer<Type>
Type * CMutablePointer<Type>
对于作为返回类型、变量和参数类型的指针,有如下映射关系:
C Syntax Swift Syntax
void * COpaquePointer
Type * UnsafePointer<Type>
对于类的指针,有如下映射关系:
C Syntax Swift Syntax
Type * const * CConstPointer<Type>
Type * __strong * CMutablePointer<Type>
Type ** AutoreleasingUnsafePointer<Type>
以上的Type是一个占位类型,可以代表任意类型。
2.4 宏定义和条件编译
C语言使用#define定义的基本常量在导入Swift时被Swift编译器自动转换为Swift 语言的全局变量。但复杂的宏定义不能被Swift转换。
Swift代码也支持条件编译,如下所示:
#if build configuration && !build configuration
statements
#elseif build configuration
statements
#else
statements
#endif
三、 与Interface Builder集成
在Swift也是使用@IBOutlet@IBAction来定义Outlets属性和Actions动作,用来实现代码与用户接口对象的连接。如下所示,在MyViewController类中声明了与用户接口对象连接的一个outlet属性、一个outlet属性数组、一个action动作。
class MyViewController:UIViewController
{@IBOutlet var button:UIButton
@IBOutlet var textFields:UITextField[]
@IBAction func buttonTapped(AnyObject)
{println("button
tapped!")}
}
当使用@IBOutlet来声明一个outlet时,Swift自动把它转换为一个弱引用隐含型的已展开选项类型,并分配它的初始值为nil。
Swift中使用@IBDesignable属性来声明一个能够在Interface Builder中使用的特定视图对象,使用@IBInspectable属性声明一个可以在Interface Builder中的inspector中进行编辑的视图属性。如下所示声明了一个视图和相关的属性:
@IBDesignable
class MyCustomView:UIView
{@IBInspectable var textColor:UIColor
@IBInspectable var iconHeight:CGFloat
/* ... */
}
四、 混合使用Swift与Objective-C语言
在一个单独的工程中,还能够同时包含Objective-C和Swif文件。
为了使一组Objective-C文件被相同应用工程中的Swif文件使用,需要使用Xcode创建一个Objective-C桥接头文件,并在桥接头文件中导入每一个被Swift用到的Objective-C头文件。桥接头文件的名字为产品名字加“-Bridging-Header.h”后缀。
OBJECTIVE-C头文件
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import “XYZCustomViewController.h"
Objective-C桥接头文件中添加的Objective-C头文件中定义的功能将能够自动被相同工程的Swift文件使用。
Objective-C代码需要使用相同应用工程中的Swift代码时,Xcode自动产生一个包含相同工程中所有Swift文件接口声明的Objective-C 头文件,接口文头件为产品模块名字加“-Swift.h”后缀。
然后在要使用Swift代码的Objective-C文件中采用如下形式导入该头文件。
#import “ProductModuleName-Swift.h”
然后该Objective-C文件将可使用相同工程中的所有Swift文件中公开的功能。
为了在一个Objective-C头文件中引用一个Swift类,需要使用@class在引用前面对该类进行声明。如下所示:
OBJECTIVE-C
// MyObjcClass.h
@class MySwiftClass;
@interface MyObjcClass
:NSObject- (MySwiftClass *)return SwiftObject;
/* ... */