【編者按:】在今年的 WWDC 2014大會上,蘋果公司發(fā)布了Swift。Swift語言不僅繼承了C語言以及Objective-C的特性,而且還克服了C語言的兼容性問題,對于廣大開發(fā)者來說是個(gè)不錯(cuò)的選擇。然而,原文作者Tyrone卻并不待見Swift,他在使用Swift的過程中,發(fā)現(xiàn)Swift并沒有想象中的美好。究竟是什么原因呢?一起來看下:
譯文如下:
在進(jìn)行測試前,我作了如下思考:
我這里主要以一個(gè)Swift項(xiàng)目為基礎(chǔ),進(jìn)行性能測試。以下是一個(gè)相關(guān)示例代碼:
import Foundation public class User : ModelObject, UpdatableFromJSON { public var name: String? public var handle: String? public required init(data: [String : AnyObject]) { super.init(data: data) updateWithJSON(data) } public override func updateWithJSON(data: [String : AnyObject]) { super.updateWithJSON(data) name <<< data["name"] handle <<< data["handle"] } }
這是一個(gè)用于分析500KB大小JSON數(shù)據(jù)的示例,完整的示例代碼請點(diǎn)擊 這里 進(jìn)行下載,示例處理的問題是在1000個(gè)會話中找出用戶User對應(yīng)的會員身份。解析器parser讀取JSON后,創(chuàng)建Membership對象并指向關(guān)聯(lián)實(shí)例User和Convo ,同時(shí)根據(jù)convos鍵值創(chuàng)建(或更新)Convo對象堆。
我利用了XCTest的新特性進(jìn)行了性能測試。測試代碼如下所示:
func testUserConvosSwiftParsingPerformance() { let filePath = NSBundle(forClass: PerformanceTests.self).pathForResource("convos", ofType: "json") let jsonData = NSData(contentsOfFile: filePath!) var error: NSError? let jsonObject = NSJSONSerialization.JSONObjectWithData(jsonData!, options: nil, error: &error)! as [String : AnyObject] self.measureBlock() { let resp = ChatspryClient.UserConvosResponse(data: jsonObject) } }
我在編譯設(shè)置中開啟了-O模式,測試的設(shè)備是第五代iPod Touch,運(yùn)行的系統(tǒng)是iOS 8,使用的是與iPhone4S相同的A5雙核處理器。隨著JSON數(shù)據(jù)處理量的增加,該設(shè)備的響應(yīng)越來越慢。
測試結(jié)果是用時(shí)1.42s,多么令人吃驚的龜速。于是,我決定馬上創(chuàng)建一個(gè)Objective-C版本來進(jìn)行對比。
@interface CSUser : CSModelObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *handle; @end @implementation CSUser - (void) updateWithJSON:(NSDictionary *)json { [super updateWithJSON: json]; self.name = json[@"name"]; self.handle = json[@"handle"]; } @end
同樣地我啟用了-Os。令人驚喜的是,這個(gè)版本的運(yùn)行用時(shí)僅需0.09s,換而言之,它大約比Swift快了將近15倍,而我在Swift和Object-C都已經(jīng)開啟了LLVM優(yōu)化器。
我嘗試對Swift的反常表現(xiàn)進(jìn)行簡單研究,我暫時(shí)還不能確定這究竟是Swift本身的原因還是JSONHelpder引起的。唯一的方法是一行行地比照Objective-C語句和Swift語句,再寫另一個(gè)Objective-C樣式的Swift,然后進(jìn)行Apples To Apples的測試。這或許不是常規(guī)的Swift寫法,隨處都是NSDictionary引用而不是Swift 本身的函數(shù)。例如:
public class CSSwiftUser : CSSwiftModelObject { public var name: String? public var handle: String? public override func updateWithJSON(json: NSDictionary) { super.updateWithJSON(json) name = json["name"] as String? handle = json["handle"] as String? } }
Swift在-O下運(yùn)行時(shí)會有segfaults(段錯(cuò)誤)的情況,為了公平起見,我把Object-C優(yōu)化器關(guān)閉了,這是關(guān)閉后兩者的比較:
讓我較迷惑的是Objective-C在關(guān)閉優(yōu)化器后反而運(yùn)行得更快,這個(gè)先放下,不是這次的重點(diǎn)。由上可見,Objective-C樣式的Swift獲得了可接受的性能表現(xiàn),但是如果真的這樣做,段錯(cuò)誤會不斷出現(xiàn),最后導(dǎo)致性能下降。
出于好奇,最后我還使用了RubyMotion以Ruby語言重寫Objective-C測試。RubyMotion支持使用Ruby來編寫iOS 和安卓應(yīng)用,程序最后會被編譯為相同的機(jī)器碼,與Swift和Objective-C過程類似。一直以來,我認(rèn)為Ruby會比Objective-C慢得多,畢竟這是動(dòng)態(tài)和靜態(tài)語言的區(qū)別。
該Ruby示例代碼如下:
class CSUser < CSModelObject attr_accessor :name, :handle def updateWithJSON(json) super self.name = json[:name] self.handle = json[:handle] end end
注:RubyMotion中暫時(shí)沒有任何的優(yōu)化設(shè)置選項(xiàng)。
最后的測試結(jié)果是:
可見,RubyMotion比Swift跑得更快。因此,Swift是不是真的如宣傳所說的那樣身手敏捷,真的見仁見智了。不過對于我來說,如果沒有進(jìn)一步的改進(jìn),我決定還是使用Objective-C來編寫iOS項(xiàng)目好了。