在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 的Factory 方法在匯入Swift時被自動對應為Swift語言的便利初始化方法。例如在Objective-C中如下調用一個Factory 方法。
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 CChar
unsigned char CUnsignedChar
short CShort
unsigned short CUnsignedShort
int CInt
unsigned int CUnsignedInt
long CLong
unsigned long CUnsignedLong
long long CLongLong
unsigned long long CUnsignedLongLong
wchar_t CWideChar
char16_t CChar16
char32_t CChar32
float CFloat
double 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 * CMutablePointer
對於作為傳回型別、變數和參數類型的指標,有如下映射關係:
C Syntax Swift Syntax
void * COpaquePointer
Type * UnsafePointer
對於類的指標,有如下映射關係:
C Syntax Swift Syntax
Type * const * CConstPointer
Type * __strong * CMutablePointer
Type ** AutoreleasingUnsafePointer
以上的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;
/* ... */