雖然說Swift語言的初衷是希望能擺脫Objective-C的沉重的歷史包袱和約束,但是不可否認的是經過了二十多年的洗禮,Cocoa框架早就烙上了不可磨滅的Objective-C的印記。無數的第三方庫是用Objective-C寫成的,這些積累無論是誰都不能小覷。因此,在最初的版本中,Swift不得不考慮與Objective-C的兼容。
Apple採取的做法是允許我們在同一個項目中同時使用Swift和Objective-C來進行開發。其實一個項目中的Objective-C文件和Swift文件是處於兩個不同世界中的,為了讓它們能相互聯通,我們需要添加一些橋梁。
首先通過添加{product-module-name}-Bridging-Header.h文件,並在其中填寫想要使用的頭文件名稱,我們就可以很容易地在Swift中使用Objective-C代碼了。Xcode為了簡化這個設定,甚至在Swift項目中第一次導入Objective-C文件時會主動彈框進行詢問是否要自動創建這個文件,可以說是非常方便。
但是如果想要在Objective-C中使用Swift的類型的時候,事情就複雜一些。如果是來自外部的框架,那麼這個框架與Objective-C項目肯定不是處在同一個target中的,我們需要對外部的Swift module進行導入。這個其實和使用Objective-C的原來的Framework是一樣的,對於一個項目來說,外界框架是由Swift寫的還是Objective-C寫的,兩者並沒有太大區別。我們通過使用2013年新引入的@import來引入module:
@import MySwiftKit;之後就可以正常使用這個Swift寫的框架了。
如果想要在Objective-C裡使用的是同一個項目中的Swift的源文件的話,可以直接導入自動生成的頭文件{product-module-name}-Swift.h來完成。比如項目的target叫做MyApp的話,我們就需要在Objective-C文件中寫:
#import "MyApp-Swift.h"但這只是故事的開始。Objective-C和Swift在底層使用的是兩套完全不同的機制,Cocoa中的Objective-C對象是基於運行時的,它從骨子裡遵循了KVC(Key-Value Coding,通過類似字典的方式存儲對象信息)以及動態派發(Dynamic Dispatch,在運行調用時再決定實際調用的具體實現)。而Swift為了追求性能,如果沒有特殊需要的話,是不會在運行時再來決定這些的。也就是說,Swift類型的成員或者方法在編譯時就已經決定,而運行時便不再需要經過一次查找,而可以直接使用。
顯而易見,這帶來的問題是如果我們要使用Objective-C的代碼或者特性來調用純Swift的類型時候,我們會因為找不到所需要的這些運行時信息,而導致失敗。解決起來也很簡單,在Swift類型文件中,我們可以將需要暴露給Objective-C使用的任何地方(包括類,屬性和方法等)的聲明前面加上@objc修飾符。注意這個步驟只需要對那些不是繼承自NSObject的類型進行,如果你用Swift寫的class是繼承自NSObject的話,Swift會默認自動為所有的非private的類和成員加上@objc。這就是說,對一個NSObject的子類,你只需要導入相應的頭文件就可以在Objective-C裡使用這個類了。
@objc修飾符的另一個作用是為Objective-C側重新聲明方法或者變量的名字。雖然絕大部分時候自動轉換的方法名已經足夠好用(比如會將Swift中類似init(name: String) 的方法轉換成-initWithName:(NSString *)name這樣),但是有時候我們還是期望Objective-C裡使用和Swift中不一樣的方法名或者類的名字,比如Swift裡這樣的一個類:
class 我的類 { func 打招呼(名字: String) { println("哈嘍,\(名字)") }}我的類().打招呼("小明")Objective-C的話是無法使用中文來進行調用的,因此我們必須使用@objc將其轉為ASCII才能在Objective-C裡訪問:
@objc(MyClass)class 我的類 { @objc(greeting:) func 打招呼(名字: String) { println("哈嘍,\(名字)") }}這樣,我們在Objective-C裡就能調用 [[MyClass new] greeting:@"XiaoMing"] 這樣的代碼了(雖然比起原來一點都不好玩了)。另外,正如上面所說的以及在Selector一節中所提到的,即使是NSObject的子類,Swift也不會在被標記為private的方法或成員上自動加@objc。如果我們需要使用這些內容的動態特性的話,我們需要手動給它們加上@objc修飾。
添加@objc修飾符並不意味著這個方法或者屬性會變成動態派發,Swift依然可能會將其優化為靜態調用。如果你需要和Objective-C裡動態調用時相同的運行時特性的話,你需要使用的修飾符是dynamic。一般情況下在做App開發時應該用不上,但是在施展一些像動態替換方法或者運行時再決定實現這樣的 "黑魔法" 的時候,我們就需要用到dynamic修飾符了。在之後的KVO一節中,我們還會提到一個關於使用dynamic的實例。
作者:王巍(@onevcat),iOS和Unity3D開發者。
本文轉載自:Swifter
點擊連結進入Swift技術社區,了解更多Swift開發的技術熱點內容!
CSDN JOB移動工程師專場招聘,直擊20家企業高薪職位-->http://job.csdn.net/event/mobdev.html