雖說 Swift 語言的初衷是但願能擺脫 Objective-C 的沉重的歷史包袱和約束,可是不能否認的是通過了二十多年的洗禮,Cocoa 框架早就烙上了不可磨滅的 Objective-C 的印記。無數的第三方庫是用 Objective-C 寫成的,這些積累不管是誰都不能小覷。所以,在最初的版本中,Swift 不得不考慮與 Objective-C 的兼容。app
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 寫的框架了。spa
若是想要在 Objective-C 裏使用的是同一個項目中的 Swift 的源文件的話,能夠直接導入自動生成的頭文件 {product-module-name}-Swift.h 來完成。好比項目的 target 叫作 MyApp 的話,咱們就須要在 Objective-C 文件中寫code
#import "MyApp-Swift.h"
但這只是故事的開始。Objective-C 和 Swift 在底層使用的是兩套徹底不一樣的機制,Cocoa 中的 Objective-C 對象是基於運行時的,它從骨子裏遵循了 KVC (Key-Value Coding,經過相似字典的方式存儲對象信息) 以及動態派發 (Dynamic Dispatch,在運行調用時再決定實際調用的具體實現)。而 Swift 爲了追求性能,若是沒有特殊須要的話,是不會在運行時再來決定這些的。也就是說,Swift 類型的成員或者方法在編譯時就已經決定,而運行時便再也不須要通過一次查找,而能夠直接使用。htm
顯而易見,這帶來的問題是若是咱們要使用 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 的實例。