說到 Swift 會不會完全取代 Objective-C,目前看起來是,在 iOS 8 推出之後,應該不少應用程式會使用 Swift 開發,但是 Framework 這一層還是要用 Objective-C 來寫。
我們還是要回來看 Objective-C 與 Swift 的 run time 是怎麼實作的。無論是在 Objective-C 或 Swift 中,一個 class 有哪些 method,都是儲存在 virtual method table (以下簡稱 vtable)中,但是實作方式不一樣。
Objective-C 的 vtable 是個像是 dictionary 的實作,table 中每一筆資料都是 C 字串當 key(又稱 selector),對應到相對的 C Function pointer,所以每次呼叫某個 Objective-C 物件的某個 method,就是透過一個叫做 objc_msgSend 的 function,在表格中根據字串當 key,尋找對應該執行的 function—如果找不到,還會去問這個 Class 是否有實作 forwardInvocation: 這個 method,還是沒有的話,就會丟出找不到 method 的 exception,這部份可以參考蘋果自己的官方文件。
至於 Swift 的 vtable 則是一個 array,對某個物件呼叫某個 method 時,相當於要求執行這個 function array 當中的第幾個 function(參見 Mike Ash 的文章)。
如此就會造成以下影響:在 Swift 中,尋找要呼叫的 method 的速度,理論上就會比 Objective-C 來得快,因此同樣功能的程式,用 Swfit 寫,整體上應該會比用 Objective-C 來得快。但同時,Swift 的 vtable 中每個 function 的順序就不能改變,在編譯的時候,vatble 裡頭是什麼順序,在執行的時候就得要是什麼順序,如果是執行的時候載入了不同的 runtime,順序不對,那就會呼叫到錯誤的 function。
蘋果是怎麼確保 compile 時用到的 runtime 與執行時的 runtime 是同一份呢?就是,在編譯應用程式的時候,Xcode 會自動把一份 Swift runtime 複製到應用程式的 bundle 中;所以,你的裝置中有多少個 Swift 應用程式,就會有多少份 Swift runtime。Swift 的 runtime 本身不大,這麼做還沒什麼問題,但是你寫一個 iOS 應用程式還會用到 Foundation、UIKit…一大堆的 Framework,如果要把每個 Framework 都複製一份,聽起來就很不對,照裡說不會換成 Swift 才對,Objective-C 當初用字串當 key,某方面來看,也就是為了處理像 DLL Hell 這樣的問題。
外部開發者比較沒有機會寫到比較底層的 Framework,如果只是寫一個 iOS 應用程式的話,按照蘋果的宣稱,全都用 Swift 寫看來不是什麼問題。
而在 iOS 8 之後,蘋果也終於開放在應用程式 bundle 中,放置自己寫的、或別人包好的 Framework(Mac OS X 從一開始就開放了)。如果是自己寫的 Framework,而且這個 Framework 與主要應用程式的 Target 是在同一個 Xcode project 中,跟著主應用程式 Target 一起編譯,那應該還不會有什麼問題,但如果用的是別人已經編譯好的 Framrwork,那就相當危險—你不能夠保證別人的這個 Framework,與你現在的開發環境用的是同一個版本的 Swift runtime。
iOS 8 同時也開放了一些系統 extension,這些 extension 感覺起來原理就是 Mac OS X 上的 plug-in bundle,透過 dynamic loading 讀入外部的 library。感覺起來 extension 用 Swift 寫似乎也頂危險的—一個應用程式載入一堆 plug-in,每個 plug-in 可能相依於不同的 Swift runtime,看起來就會出亂子。不過目前還沒看到蘋果自己在這方面有什麼文件。