在 WWDC 14 的 Keynote 上茫藏,Swift 相比于其他語言的速度優(yōu)勢(shì)被特別進(jìn)行了強(qiáng)調(diào)。但是這種速度優(yōu)勢(shì)是有條件的凉当,雖然由于編譯器的進(jìn)步我們可能可以在不了解語言特性的時(shí)候隨便寫也能得到性能上的改善售葡,但是如果能夠稍微理解背后的機(jī)制的話,我們就能投 “編譯器所好”楼雹,寫出更高效的代碼。
相比于 Objective-C榨咐,Swift 最大的改變就在于方法調(diào)用上的優(yōu)化谴供。在 Objective-C 中,所有的對(duì)于 NSObject 的方法調(diào)用在編譯時(shí)會(huì)被轉(zhuǎn)為 objc_msgSend 方法龟劲。這個(gè)方法運(yùn)用 Objective-C 的運(yùn)行時(shí)特性轴或,使用派發(fā)的方式在運(yùn)行時(shí)對(duì)方法進(jìn)行查找照雁。因?yàn)?Objective-C 的類型并不是編譯時(shí)確定的,我們?cè)诖a中所寫的類型不過只是向編譯器的一種“建議”萍诱,不論對(duì)于怎樣的方法污呼,這種查找的代價(jià)基本都是同樣的。
這個(gè)過程的等效的表述可能類似這樣 (注意這只是一種表述籍凝,與實(shí)際的代碼和工作方式無關(guān)):
// 這個(gè)查找一般需要遍歷類的方法表苗缩,需要花費(fèi)一定時(shí)間
methodToCall = findMethodInClass(class, selector);
// 調(diào)用
methodToCall();
Objective-C 運(yùn)行時(shí)十分高效酱讶,相比于 I/O 這樣的操作來說,單次的方法派發(fā)和查找并不會(huì)花費(fèi)太多的時(shí)間渊迁,但實(shí)事求是地說灶挟,這確實(shí)也是 Objective-C 性能上可以改進(jìn)的地方,這種改善在短時(shí)間內(nèi)大量方法調(diào)用時(shí)會(huì)比較明顯。
Swift 因?yàn)槭褂昧烁踩蛧?yán)格的類型榛泛,如果我們?cè)诰帉懘a中指明了某個(gè)實(shí)際的類型的話 (注意,需要的是實(shí)際具體的類型孤个,而不是像 Any 這樣的抽象的接口)沛简,我們就可以向編譯器保證在運(yùn)行時(shí)該對(duì)象一定屬于被聲明的類型。這對(duì)編譯器進(jìn)行代碼優(yōu)化來說是非常有幫助的给郊,因?yàn)橛辛烁喔鞔_的類型信息捧灰,編譯器就可以在類型中處理多態(tài)時(shí)建立虛函數(shù)表 (vtable)毛俏,這是一個(gè)帶有索引的保存了方法所在位置的數(shù)組。在方法調(diào)用時(shí)焕蹄,與原來動(dòng)態(tài)派發(fā)和查找方法不同阀溶,現(xiàn)在只需要通過索引就可以直接拿到方法并進(jìn)行調(diào)用了,這是實(shí)實(shí)在在的性能提升迹卢。這個(gè)過程大概相當(dāng)于:
// 直接使用 methodIndex 獲取實(shí)現(xiàn)
let methodToCall = class.vtable[methodIndex]
// 調(diào)用
methodToCall();
更進(jìn)一步腐碱,在確定的情況下,編譯器對(duì) Swift 的優(yōu)化甚至可以做到將某些方法調(diào)用優(yōu)化為 inline 的形式掉弛。比如在某個(gè)方法被 final 標(biāo)記時(shí)症见,由于不存在被重寫的可能,vtable 中該方法的實(shí)現(xiàn)就完全固定了殃饿。對(duì)于這樣的方法谋作,編譯器在合適的情況下可以在生成代碼的階段就將方法內(nèi)容提取到調(diào)用的地方,從而完全避免調(diào)用乎芳。
通過 Benchmark 我們可以看出遵蚜,在一些基本的算法上逻翁,Swift 的速度是要遠(yuǎn)勝過 Objective-C 的,而就算相較于世界上無可匹敵的 C理郑,也沒有遜色太多。
所以對(duì)于性能方面寂殉,我們應(yīng)該注意的地方就很明顯了囚巴。如果遇到性能敏感和關(guān)鍵的代碼部分,我們最好避免使用 Objective-C 和 NSObject 的子類友扰。在以前我們可能會(huì)選擇使用混編一些 C 或者 C++ 代碼來處理這些關(guān)鍵部分彤叉,而現(xiàn)在我們多了 Swift 這個(gè)選項(xiàng)。相比起 C 或者 C++村怪,Swift 的語言特性上要先進(jìn)得多秽浇,而使用 Swift 類型和標(biāo)準(zhǔn)庫進(jìn)行編碼和構(gòu)建的難度,比起使用 C 或 C++ 來要簡(jiǎn)單太多实愚。另外兼呵,即使不是性能關(guān)鍵部分,我們也應(yīng)該盡量考慮在沒有必要時(shí)減少使用 NSObject 和它的子類腊敲。如果沒有動(dòng)態(tài)特性的需求的話击喂,保持在 Swift 基本類型中會(huì)讓我們得到更多的性能提升。
更多文章
CocoaPods開源庫的搭建
CocoaPods搭建私有庫
CocoaPods搭建私有庫遇到問題
CocoaPods私有庫的升級(jí)維護(hù)
SKStoreReviewController之程序內(nèi)評(píng)價(jià)
App應(yīng)用程序圖標(biāo)的動(dòng)態(tài)更換
開源框架 MGJRouter_Swift
iOS的MVP設(shè)計(jì)模式
iOS插件化
iOS FMDB的使用
Swift之ReactiveSwift
OC之ReactiveCocoa
OC之ReactiveCocoa進(jìn)階
iOS 性能考慮