[翻譯]關于Swift的編譯時間優(yōu)化

原文鏈接:Regarding Swift build time optimizations

上周站玄,在我讀完 @nickoneill 寫的一篇優(yōu)秀的博文《為緩慢的Swift編譯時間提速》后,我發(fā)現用一個不同的角度去審視 Swift 代碼并不是很難的一件事介袜。

可以被認為是簡潔的一行代碼現在引發(fā)了一個新的問題 -- 是否應該把這行代碼重構成對應的9行代碼以讓編譯器更容易工作(看看接下來要講的關于空合運算符(nil coalescing operator)的示例)仪芒?到底哪個才是更重要的唁影,簡潔的代碼還是對編譯器友好的代碼耕陷?這取決于項目的大小和開發(fā)者的想法。

慢著据沈。哟沫。。這里有一個 Xcode 插件

在展示具體的例子之前卓舵,我先想到就是手動查看日志是一件非常耗時的事情南用。有人提出了用終端命令可以讓這件事情變得比較容易,但是我更進一步掏湾,把這個用 Xcode 插件 給實現出來了裹虫。

Xcode插件.png

對我來說,最初的目的就是找到并修復最耗時的地方融击,但我現在的想法是讓它經歷更多的迭代過程筑公。這樣的話我就不僅可以讓代碼編譯更有效率,還可以防止第一次進入項目的耗時尊浪。

更加驚喜的是

我經常在多個 Git 分支間跳來跳去匣屡,等待一個緩慢的項目編譯完成往往浪費了大量的時間。我想了好長一段時間為什么我的一個寵物項目會編譯地這么緩慢(大概2萬行 Swift 代碼)拇涤。

在我學習了究竟是原因導致的這件事之后捣作,我不得不承認我的確很吃驚,一行代碼就需要幾秒鐘來編譯鹅士。

讓我們一起看看幾個例子券躁。

空合操作符

編譯器是很不喜歡這里的第一種方式的。在展開下面兩處簡寫的代碼之后掉盅,編譯時間減少了99.4%也拜。

// 編譯時間: 5238.3ms
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)

// 編譯時間: 32.4ms
var padding: CGFloat = 22
if let rightView = rightView {
    padding += rightView.bounds.width
}

if let leftView = leftView {
    padding += leftView.bounds.width
}
return CGSizeMake(size.width + padding, bounds.height)

ArrayOfStuff + [Stuff]

這個看起來像下面這樣:

return ArrayOfStuff + [Stuff]
// 而不是
ArrayOfStuff.append(stuff)
return ArrayOfStuff

我經常這樣做,每次都會對所需的編譯時間產生影響趾痘。下面是最差的一個慢哈,這里的編譯時間減少了97.9%。

// 編譯時間: 1250.3ms
let systemOptions = [ 7, 14, 30, -1 ]
let systemNames = (0...2).map{ String(format: localizedFormat, systemOptions[$0]) } + [NSLocalizedString("everything", comment: "")]
// 一些中間的代碼
labelNames = Array(systemNames[0..<count]) + [systemNames.last!]

// 編譯時間: 25.5ms
let systemOptions = [ 7, 14, 30, -1 ]
var systemNames = systemOptions.dropLast().map{ String(format: localizedFormat, $0) }
systemNames.append(NSLocalizedString("everything", comment: ""))
// 一些中間的代碼
labelNames = Array(systemNames[0..<count])
labelNames.append(systemNames.last!)

三元運算符

僅僅只是把三元運算符替換成 if-else 語句永票,就讓編譯時間減少了92.9%卵贱。如果將 map 換成 for 循環(huán),就又能減少75%(但是那樣的話我的眼睛可就受不了了)瓦侮。??

// 編譯時間: 239.0ms
let labelNames = type == 0 ? (1...5).map{type0ToString($0)} : (0...2).map{type1ToString($0)}

// 編譯時間: 16.9ms
var labelNames: [String]
if type == 0 {
    labelNames = (1...5).map{type0ToString($0)}
} else {
    labelNames = (0...2).map{type1ToString($0)}
}

轉換 CGFloat 到 CGFloat

沒聽懂我在說什么艰赞?其實下面例子中值已經是 CGFloat 了,并且有些括號是多余的肚吏。在清理完這些冗余之后方妖,編譯時間減少了99.9%。

// 編譯時間: 3431.7 ms
return CGFloat(M_PI) * (CGFloat((hour + hourDelta + CGFloat(minute + minuteDelta) / 60) * 5) - 15) * unit / 180

// 編譯時間: 3.0ms
return CGFloat(M_PI) * ((hour + hourDelta + (minute + minuteDelta) / 60) * 5 - 15) * unit / 180

Round()

下面是一個很奇怪的例子罚攀,下面的例子中變量是一個局部變量與實例變量的混合党觅。這個問題似乎不是出在四舍五入本身雌澄,而是在于結合代碼的方法。去掉四舍五入的方法大概能減少 97.6% 的構建時間杯瞻。

// 編譯時間: 1433.7ms
let expansion = a — b — c + round(d * 0.66) + e
// 編譯時間: 34.7ms
let expansion = a — b — c + d * 0.66 + e

注意:以上所有測試都在MacBool Air(13英寸镐牺,2013年中)上進行。

嘗試一下吧

不管你是否面臨過編譯時間太長的問題魁莉,編寫對編譯器友好的代碼都是非常有用的睬涧。我確信你會在其中找到一些驚喜。作為參考旗唁,這里有完整的代碼畦浓,我的工程中可以5秒內完成編譯…

import UIKit

class CMExpandingTextField: UITextField {

    func textFieldEditingChanged() {
        invalidateIntrinsicContentSize()
    }
    
    override func intrinsicContentSize() -> CGSize {
        if isFirstResponder(), let text = text {
            let size = text.sizeWithAttributes(typingAttributes)
            return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)
        }
        return super.intrinsicContentSize()
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市检疫,隨后出現的幾起案子讶请,更是在濱河造成了極大的恐慌,老刑警劉巖屎媳,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺溢,死亡現場離奇詭異,居然都是意外死亡烛谊,警方通過查閱死者的電腦和手機风响,發(fā)現死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丹禀,“玉大人钞诡,你說我怎么就攤上這事∨缺溃” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵接箫,是天一觀的道長攒读。 經常有香客問我,道長辛友,這世上最難降的妖魔是什么薄扁? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮废累,結果婚禮上邓梅,老公的妹妹穿的比我還像新娘。我一直安慰自己邑滨,他們只是感情好日缨,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掖看,像睡著了一般匣距。 火紅的嫁衣襯著肌膚如雪面哥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天毅待,我揣著相機與錄音尚卫,去河邊找鬼。 笑死尸红,一個胖子當著我的面吹牛吱涉,可吹牛的內容都是我干的。 我是一名探鬼主播外里,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼怎爵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了级乐?” 一聲冷哼從身側響起疙咸,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎风科,沒想到半個月后撒轮,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡贼穆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年题山,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片故痊。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡顶瞳,死狀恐怖,靈堂內的尸體忽然破棺而出愕秫,到底是詐尸還是另有隱情慨菱,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布戴甩,位于F島的核電站符喝,受9級特大地震影響,放射性物質發(fā)生泄漏甜孤。R本人自食惡果不足惜协饲,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缴川。 院中可真熱鬧茉稠,春花似錦、人聲如沸把夸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吞获,卻和暖如春况凉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背各拷。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工刁绒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烤黍。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓知市,卻偏偏與公主長得像,于是被迫代替她去往敵國和親速蕊。 傳聞我的和親對象是個殘疾皇子嫂丙,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容

  • 關于 Swift 重要這個文檔所包含的準備信息, 是關于開發(fā)的 API 和技術的。這個信息可能會改變, 根據這個文...
    無灃閱讀 4,283評論 1 27
  • 發(fā)現 關注 消息 iOS 第三方庫规哲、插件跟啤、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 有句話袄简,我是第一次說腥放,而且只說一次:" 這樣確切的愛,一生只有一次绿语,我今天才知道秃症,我之所以瓢潑就是為你。"——《廊...
    我行我素的兔閱讀 1,242評論 0 2
  • 1吕粹、自我目標管理 - 將大的目標細化成一個個小的目標 - 每個目標要有明確的事項和時限 - 杜絕懶惰 2种柑、自我知識...
    jasonlam閱讀 253評論 0 1
  • 文/ 莫菲 一.歷史殘留的印記 幾年間,世俗滄桑變化很大匹耕,沒有了歷史的爆炸性戰(zhàn)爭莹规,卻也有歷史遺留下的精神財富。我...
    莫琴曉曉閱讀 468評論 0 2