99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
一葉知秋 頭像
蘋(píng)果2袋
2
一葉知秋

Uber 使用 Swift 重寫(xiě) App 的踩坑經(jīng)歷及解決方案

發(fā)布時(shí)間:2017-05-23 11:12  回復(fù):0  查看:2047   最后回復(fù):2017-05-23 11:12  

  本文出自Uber移動(dòng)架構(gòu)和框架組負(fù)責(zé)人托馬斯·阿特曼于2016年在灣區(qū)Swift峰會(huì)上的演講,分享了使用Swfit重寫(xiě)Uber的好與壞。以下為譯文:

  我是托馬斯·阿特曼,目前是Uber移動(dòng)架構(gòu)和框架組負(fù)責(zé)人。Uber現(xiàn)在的用戶量已經(jīng)達(dá)到數(shù)百萬(wàn),這么大的用戶量,Uber是如何用框架實(shí)現(xiàn)的呢?

  Swift與百位工程師的故事 — 原因、架構(gòu)、經(jīng)驗(yàn)

  今天我想談?wù)勔话俣嗝鸘ber工程師是如何使用Swift編程語(yǔ)言的,在上周三新發(fā)布的Rider App主應(yīng)用程序全部都是用Swift語(yǔ)言重構(gòu)的。接下來(lái)我的分享主要包括三個(gè)部分:選擇Swift的原因、Uber新架構(gòu);重構(gòu)經(jīng)驗(yàn)。

  優(yōu)步的開(kāi)端——重構(gòu)的原因

  這是整個(gè)移動(dòng)團(tuán)隊(duì)四年前的樣子(指向屏幕顯示有三名工程師的照片),就是從那時(shí)開(kāi)始,他們著手搭建了我們現(xiàn)在這套老應(yīng)用的基礎(chǔ)。老的應(yīng)用程序已經(jīng)穩(wěn)定使用了四年,但由于移動(dòng)開(kāi)發(fā)團(tuán)隊(duì)的指數(shù)級(jí)的增長(zhǎng),這套架構(gòu)的缺點(diǎn)也逐漸顯示出來(lái),基于這套老架構(gòu)想做功能開(kāi)發(fā)也變得越來(lái)越困難。由于跟不同團(tuán)隊(duì)之間共用了很多ViewController,所以每次也需要對(duì)其它的代碼進(jìn)行測(cè)試。老架構(gòu)真正讓我們感到崩潰的主要原因是它是由兩位工程師寫(xiě)出來(lái)的,但是目前團(tuán)隊(duì)已經(jīng)發(fā)展到了100多人。與此同時(shí),那套產(chǎn)品本身的用戶量也不大。我們已經(jīng)在多個(gè)城市開(kāi)始運(yùn)行,產(chǎn)品滑塊底部密集的問(wèn)題也顯示出來(lái)了,原因就是因?yàn)樗械膱F(tuán)隊(duì)都希望在他們所在的城市能夠推出新的產(chǎn)品。我們也想對(duì)Rider App做一套全新的用戶體驗(yàn)界面?;谏鲜龅倪@些問(wèn)題,其實(shí)歸納起來(lái)也就是目前那套應(yīng)用的架構(gòu)問(wèn)題和用戶體驗(yàn)界面的全新設(shè)計(jì)問(wèn)題。未來(lái)不再是研究老架構(gòu)然后去解決問(wèn)題這種形式了,而是一切都從頭開(kāi)始。

  2015年做了很多糾正錯(cuò)誤工作,試圖去完善老的結(jié)構(gòu),但對(duì)Uber的全新設(shè)計(jì),將會(huì)從根本上解決問(wèn)題,到時(shí)會(huì)處于一個(gè)更安全的階段,從頭去重新設(shè)計(jì)也是最理想的一種解決問(wèn)題的方式。

  重構(gòu)架構(gòu)的目標(biāo)——穩(wěn)定可靠并且支持未來(lái)發(fā)展

  基于這兩個(gè)重構(gòu)原因開(kāi)始了新架構(gòu)的研發(fā)。最基本的需求就是滿足上述兩個(gè)要求,保證四條核心流程的穩(wěn)定,這基本上就意味著崩潰率處于最低級(jí)別。 如果您的應(yīng)用程序沒(méi)有崩潰,但用戶仍然停留在某些屏幕上,顯然這問(wèn)題很重大,這會(huì)讓用戶覺(jué)得不可靠。

  我們當(dāng)然也希望新開(kāi)發(fā)的架構(gòu)能夠支持Uber接下來(lái)數(shù)年的發(fā)展,就像當(dāng)時(shí)設(shè)計(jì)這套老架構(gòu)的時(shí)候是為了滿足過(guò)去這四年發(fā)展的想法是一樣的。

  Swift成為了我們的選擇

  為了實(shí)現(xiàn)上述的兩個(gè)目標(biāo),我們選擇了Swift。當(dāng)時(shí)我們認(rèn)為Swift是更加安全的,至少在設(shè)想里是的,然而實(shí)際生活中并沒(méi)有人去驗(yàn)證這一點(diǎn)。

  我們認(rèn)為編譯器中的類(lèi)型安全性會(huì)讓問(wèn)題更早的暴露出來(lái),而不是等到產(chǎn)品上線以后再出現(xiàn)問(wèn)題。

  而我們知道,從現(xiàn)在開(kāi)始的這四年,Swift將會(huì)進(jìn)入到一段黃金發(fā)展期,它將會(huì)成為蘋(píng)果公司未來(lái)唯一一門(mén)大力推廣的語(yǔ)言。

  時(shí)間線

  從今年年初開(kāi)始啟動(dòng)的,在二月份的時(shí)候,我們當(dāng)時(shí)還希望我們所做的事情是正確的,因?yàn)橛幸恍┕こ處熢谝郧暗墓揪突ㄙM(fèi)了大量的時(shí)間去做重構(gòu)的事,但最終都以失敗告終。為了保證重構(gòu)能成功,挑選出了幾位核心工程師,讓他們花了5個(gè)月的時(shí)間去研究老的架構(gòu),在這5個(gè)月的時(shí)間內(nèi),我們就只干這一件事:架構(gòu),框架,完成一些基礎(chǔ)的工作,最終搭建了一套很完美的基礎(chǔ)框架,所有人都是以這套基礎(chǔ)框架為原型進(jìn)行開(kāi)發(fā)。

  6月,架構(gòu)搭建好,開(kāi)始讓核心流團(tuán)隊(duì)開(kāi)始使用。核心流打算采用一種新的uberX騎行或者是uberPOOL騎行,因此我們?cè)黾恿?0位工程師,花了兩個(gè)月的時(shí)間去審查新的架構(gòu),確保我們提出來(lái)的東西與之前構(gòu)建一款新產(chǎn)品的要求是吻合的。事實(shí)證明,與最開(kāi)始的產(chǎn)品要求相比,的確遺漏了一些東西,比如在視圖層,一旦工程師開(kāi)始進(jìn)行轉(zhuǎn)換或者做一些復(fù)雜的視圖操作,那么我們必須調(diào)整架構(gòu)以滿足他們的需求。但是過(guò)了兩個(gè)月,我們?nèi)〉昧诵碌倪M(jìn)展,我們不再需要對(duì)代碼庫(kù)進(jìn)行大量遷移,并且把平臺(tái)開(kāi)放給了每一個(gè)人,如果他們需要的話,也可以移交他們的功能了。

  新架構(gòu)

  新架構(gòu)叫”Riblets”,它是由Router、Interaction、Builder、Presenter、View這幾個(gè)核心組件構(gòu)成的,這也是VIPER框架的一種思想。我們研究了VIPER、MVVM和MVC,最終提出的方案是在VIPER基礎(chǔ)之上增加一些我們自己創(chuàng)新的元素在里面。最終目標(biāo)就是將每個(gè)功能模塊化,并且每一個(gè)模塊可以獨(dú)立的進(jìn)行測(cè)試。Riblet框架里的每一個(gè)核心組件都有一個(gè)協(xié)議接口,所以開(kāi)發(fā)者可以把每一個(gè)單元單獨(dú)拿出來(lái),對(duì)它進(jìn)行充分的測(cè)試。Riblets框架里的每一個(gè)模塊都會(huì)在樹(shù)里面進(jìn)行管理,因此沒(méi)有狀態(tài)機(jī),取而代之的是一個(gè)狀態(tài)樹(shù)。狀態(tài)樹(shù)里面的每一個(gè)節(jié)點(diǎn)就是一個(gè)Riblet,新架構(gòu)中的核心部分是基于業(yè)務(wù)邏輯的,而不是視圖邏輯,并且所有的業(yè)務(wù)邏輯都是由本地決定的。

Uber 使用 Swift 重寫(xiě) App 的踩坑經(jīng)歷及解決方案

  以這張樹(shù)形圖里的“注冊(cè)”模塊為例,并不知道它的父節(jié)點(diǎn)是誰(shuí),但是它所需要的都已經(jīng)注入進(jìn)來(lái)了,是它的父節(jié)點(diǎn)注入了它所需要依賴的東西,可能還會(huì)有一個(gè)監(jiān)聽(tīng)器正在監(jiān)聽(tīng)注冊(cè)流,但是監(jiān)聽(tīng)器是不知道注冊(cè)模塊位于樹(shù)的哪里。所以說(shuō),這些模塊是完全獨(dú)立的,每一個(gè)單獨(dú)的模塊都會(huì)做本地決策。再比如,從“App”模塊開(kāi)始,它僅僅只負(fù)責(zé)一個(gè)業(yè)務(wù)模塊:“目前系統(tǒng)是否有session令牌”,這就是它監(jiān)聽(tīng)的唯一一件事,如果App模塊發(fā)現(xiàn)在流里面沒(méi)有session,它就會(huì)把路徑指向到“Welcome”處;如果它發(fā)現(xiàn)了有session,那么它就會(huì)跳過(guò)“Welcome”模塊,直接進(jìn)入到“Bootstrap”模塊。

  之后,樹(shù)形圖里面右邊的每一個(gè)組件都知道系統(tǒng)目前是處于“已登錄”狀態(tài),它們都會(huì)有一個(gè)令牌,它們都可以從獨(dú)立注入中取到session令牌,它們也沒(méi)必要去關(guān)心用戶是否已經(jīng)退出了。如果在下面的某一個(gè)節(jié)點(diǎn)處突然進(jìn)來(lái)了一個(gè)網(wǎng)絡(luò)電話,并且最終導(dǎo)致了session無(wú)效,那么App組件就會(huì)監(jiān)聽(tīng)到,它就會(huì)通過(guò)流被調(diào)用,然后知道系統(tǒng)目前是沒(méi)有session的狀態(tài),緊接著App組件就會(huì)中斷Bootstrap樹(shù),并且最終將流指向Welcome組件。

  這就可以讓不同團(tuán)隊(duì)之間只關(guān)注自己負(fù)責(zé)的那部分業(yè)務(wù),而沒(méi)有必要說(shuō)每做一步都需要去跟其他團(tuán)隊(duì)進(jìn)行溝通交流。每個(gè)團(tuán)隊(duì)都可以做出自己的本地決策,并且依賴關(guān)系始終得到滿足。

  多個(gè)文件里面的多行代碼

  開(kāi)發(fā)過(guò)程中會(huì)產(chǎn)生很多代碼,每一個(gè)模塊之間我們都定義了協(xié)議。有些組件會(huì)關(guān)聯(lián)一個(gè)Riblit,同時(shí)又關(guān)聯(lián)5個(gè)不同的文件,因此在代碼庫(kù)里面會(huì)有五千多個(gè)文件,同時(shí)還有五十多萬(wàn)行代碼。此外還有一些核心組件是用的Objective-C,這也是完全沒(méi)問(wèn)題的。

  學(xué)習(xí)過(guò)程中的經(jīng)驗(yàn)

  在學(xué)習(xí)Swift的過(guò)程中,我們也得到了一些經(jīng)驗(yàn)。

  • 好的一面

  很顯然Swift是一門(mén)更好的語(yǔ)言,也正因?yàn)檫@一點(diǎn),我們才有了一個(gè)很好的開(kāi)端,我們幾乎用到了Swift提供的所有的功能。

  1. 可靠性

  Swift的可靠性是它帶給我們的第一件驚喜,好像是在框架研發(fā)的四個(gè)月內(nèi),我突然發(fā)現(xiàn)在整個(gè)研發(fā)的過(guò)程中,我的集成開(kāi)發(fā)工具還有我的應(yīng)用都沒(méi)出現(xiàn)崩潰現(xiàn)象,即使是在調(diào)試的模式下。我問(wèn)了團(tuán)隊(duì)里面的其它成員,他們的回答都是沒(méi)有出現(xiàn)崩潰。而在整個(gè)開(kāi)發(fā)過(guò)程中,第一次出現(xiàn)崩潰是我們嘗試著用了一臺(tái)32位的機(jī)器,最終導(dǎo)致在解析JSON時(shí)出現(xiàn)了整數(shù)溢出。那是整個(gè)開(kāi)發(fā)周期中出現(xiàn)的第一次崩潰現(xiàn)象。

Uber 使用 Swift 重寫(xiě) App 的踩坑經(jīng)歷及解決方案

  Swift的可靠性讓我們感到非常的振奮,最終的數(shù)據(jù)顯示絕對(duì)無(wú)故障率是99.99%,這已經(jīng)很接近100%了。一個(gè)應(yīng)用的第一次運(yùn)行就幾乎是沒(méi)有出現(xiàn)崩潰,這種情況我還從來(lái)沒(méi)遇到過(guò)。

  必須考慮的一件事是不能允許其他人無(wú)條件對(duì)新應(yīng)用進(jìn)行解壓,正因這樣,也就不會(huì)有99.99%的絕對(duì)無(wú)故障率了,所以我們放了一個(gè)linting在里面,從而確保沒(méi)有人可以在任何條件下進(jìn)行解壓。

  你必須考慮到所有的臨界情況,就好比你寫(xiě)了很多if,但是沒(méi)有對(duì)應(yīng)的else,那應(yīng)用程就有可能出現(xiàn)異常,因此在調(diào)試階段必須使用聲明,最終上線時(shí)需要去掉,這樣應(yīng)用程序就很少會(huì)出現(xiàn)崩潰。

  • 糟糕的一面

  現(xiàn)在我們需要說(shuō)一些糟糕的事情了,但如果你能從失敗中和逆境中得到成長(zhǎng),這也是非常有意義的。

  1. 艱難的測(cè)試

  首先,如何進(jìn)行測(cè)試就是一件很困難的事。Swift是一門(mén)靜態(tài)語(yǔ)言,因此就沒(méi)有辦法像在Objective-C開(kāi)發(fā)中那樣去依靠mock測(cè)試框架進(jìn)行測(cè)試。由于都是基于協(xié)議的形式進(jìn)行開(kāi)發(fā),并且協(xié)議還是以我們這邊為主,因此我們必須找出針對(duì)這些協(xié)議的測(cè)試方案。舉個(gè)例子,這個(gè)協(xié)議是用來(lái)為實(shí)現(xiàn)類(lèi)創(chuàng)建的一個(gè)接口,這個(gè)接口允許你根據(jù)一個(gè)key進(jìn)行數(shù)據(jù)保存,也允許你根據(jù)這個(gè)key進(jìn)行檢索數(shù)據(jù),如果你有了交互器,想對(duì)一些業(yè)務(wù)邏輯進(jìn)行測(cè)試,比如當(dāng)它得到某些輸入值的時(shí)候,是否能夠?qū)⑦@些值保存到硬盤(pán)當(dāng)中,那你就必須得有一個(gè)實(shí)現(xiàn)者,也必須得有一個(gè)模擬這種存儲(chǔ)場(chǎng)景的頁(yè)面,有了這些東西,你才能測(cè)試哪一個(gè)方法被調(diào)用了。我們開(kāi)始手動(dòng)創(chuàng)建這些模擬,開(kāi)始編寫(xiě)代碼,最終得到不可擴(kuò)展這個(gè)結(jié)論。 我們不能為多個(gè)工程師都提供支持。

  我們所做的就是生成了一個(gè)小腳本,這個(gè)小腳本就是負(fù)責(zé)把大腳本給轉(zhuǎn)換成小腳本。雖然它自身也有一些問(wèn)題,但最終我們都解決掉了,無(wú)論你在哪個(gè)環(huán)節(jié)想生成測(cè)試內(nèi)容,只需引入/generate-mocks。它將會(huì)通過(guò)你的源碼,去協(xié)議里面查找?guī)в蠤CreateMock的那些聲明,希望Swift在某種程度上給我們提供屬性,并為你創(chuàng)建mocks。所以當(dāng)你通過(guò)代碼庫(kù)運(yùn)行時(shí),這份協(xié)議最終會(huì)變成一個(gè)StoringMock,它實(shí)現(xiàn)了存儲(chǔ)。它所做的就是實(shí)現(xiàn)協(xié)議里面所有共有的方法。如果你想知道這份協(xié)議被調(diào)用了多少次,它還提供了計(jì)數(shù)功能。它將會(huì)為你實(shí)現(xiàn)所有的實(shí)際的方法,無(wú)論何時(shí)它都有可能返回一個(gè)默認(rèn)的類(lèi)型。例如在dataForKey中,你有一個(gè)可選的NSData,而mock只返回nil,因?yàn)檫@是完美的。它符合接口,如果要排序測(cè)試您的輸入,您也可以隨時(shí)調(diào)用dataForKeyHandlers,將其設(shè)置為關(guān)閉,并且可以在測(cè)試中測(cè)試您從測(cè)試中得到正確的輸入。

  同樣的原理,storageDataForKey返回一個(gè)StorageResult,它是枚舉類(lèi)型的,默認(rèn)情況下會(huì)返回枚舉中的第一個(gè)成員。測(cè)試工作的問(wèn)題就解決了,并且還可以生成所有的mock,我大概算了一下,生成的mock大概有100,000行,這100,000行完全是自動(dòng)生成的,是不需要我們?cè)偃ナ止で么a的。

  2. 工具問(wèn)題

  另一件糟糕的事情就是開(kāi)發(fā)工具的問(wèn)題了。我們稱之為“無(wú)限索引”。我不知道為什么會(huì)出現(xiàn)這種情況,也許你已經(jīng)遇到過(guò),就是索引器一直在進(jìn)行索引。不知道為什么,它就是無(wú)法完成索引工作。與此同時(shí)它帶來(lái)的負(fù)面影響就是CPU使用率高達(dá)328%,這樣筆記本就會(huì)變熱,在不插入電源的情況下,筆記本大概只可以使用一個(gè)半小時(shí)。這真是一件奇怪的事,由于代碼每天都在增長(zhǎng),這個(gè)問(wèn)題也變得越來(lái)越嚴(yán)重。之前我們并沒(méi)有遇到過(guò)這些問(wèn)題,但是我們一旦超過(guò)了了200000或者300000行代碼,這個(gè)問(wèn)題就將會(huì)變得更加的嚴(yán)重。

  此外,IDE開(kāi)始這樣做:(屏幕顯示Xcode的視頻,慢慢鍵入的字符串)。 這不是我打字慢,而是我已經(jīng)輸入了整個(gè)字符串,但是IDE是用SourceKit對(duì)每一個(gè)關(guān)鍵筆劃進(jìn)行檢查,它可不管我寫(xiě)的代碼是不是正確的,而且此時(shí)你也根本沒(méi)辦法打字。

  解決方案:

  如果你碰到這個(gè)問(wèn)題,不妨做這樣(屏幕顯示刪除Xcode的視頻)。 您可以換成其他應(yīng)用,比如AppCode,團(tuán)隊(duì)里有些人就是使用的AppCode。 也有人是這么做的,先在AppCode中編寫(xiě)代碼,然后復(fù)制粘貼到Xcode進(jìn)行編譯,這樣也不會(huì)出現(xiàn)問(wèn)題,真是太奇怪了。當(dāng)然你也可以改善Nuclide,Nuclide是Facebook的IDE,目前還不支持Swift,但需要完善才能支持。

  我們的解決方案是增加更多的框架。 將整套應(yīng)用程序分解成多個(gè)框架,每個(gè)框架只包含很少的文件,他這樣做帶來(lái)的好處就是所有的一切都變得更快了。 因?yàn)楦鶕?jù)我們解決的經(jīng)驗(yàn)來(lái)看,如果框架里面的東西越多,工具出現(xiàn)問(wèn)題的概率也就越大。

  最開(kāi)始的時(shí)候,定義了70還是80個(gè)框架,如果想定義更多也不是什么難事。 當(dāng)然了,如果你只想編寫(xiě)代碼,不需要進(jìn)行編譯,那么也可以關(guān)閉索引功能,也有一部分人是這么做的。

  3. 二進(jìn)制文件的大小

  再來(lái)說(shuō)說(shuō)二進(jìn)制文件的大小問(wèn)題。 任何一款A(yù)pp應(yīng)用,它的大小必須控制在100M以內(nèi),如果超出了,那么就必須通過(guò)WIFI進(jìn)行下載,這樣就會(huì)遇到一些問(wèn)題。如果你的APP應(yīng)用中存在結(jié)構(gòu)體,應(yīng)用就會(huì)變大,如果列表中存在結(jié)構(gòu)體,它們會(huì)在堆棧中被創(chuàng)建出來(lái),導(dǎo)致應(yīng)用變大。最開(kāi)始的時(shí)候,我們將模型都設(shè)置成了結(jié)構(gòu)體,最終編譯出的二進(jìn)制文件好像是80M,這不是我們所希望的。

  可選的功能也會(huì)增加文件的體積,表面上這些功能你可以選擇性使用,但是其實(shí)你并不知道,編譯器已經(jīng)在后臺(tái)默默地做了很多事,編譯器必須去檢查這部分代碼,還得去解壓等等,實(shí)際上編譯出來(lái)了很多東西。

  泛型特化是我們遇到的另一個(gè)問(wèn)題。 只要你使用了泛型,如果你希望這些泛型變快,編譯器將會(huì)對(duì)它們進(jìn)行特化,最終編譯后的二進(jìn)制文件也會(huì)變大。

  Swift運(yùn)行時(shí)所依賴的那些庫(kù)文件也會(huì)包含到應(yīng)用程序中,我們對(duì)這些庫(kù)文件進(jìn)行了壓縮,最終實(shí)際大小只有4.5MB。

  解決方案:

  你可以通過(guò)優(yōu)化設(shè)置解決這個(gè)問(wèn)題。打開(kāi)O-whole-module-optimization優(yōu)化等級(jí),有時(shí)可能會(huì)將編譯文件變小,有時(shí)也會(huì)導(dǎo)致變大,這就需要你知道哪里的編譯比較消耗時(shí)間,因此我們也做了一個(gè)工具,它會(huì)將一個(gè)單獨(dú)的符號(hào)映射到一個(gè)文件,最終結(jié)合這些文件,你就可以直觀的看見(jiàn)應(yīng)用程序的文件夾結(jié)構(gòu)以及每一個(gè)Swift文件的大小。

  4. 啟動(dòng)速度

  啟動(dòng)速度是我們開(kāi)發(fā)過(guò)程中遇到的另一件棘手事情。如果你看過(guò)了蘋(píng)果全球開(kāi)發(fā)者大會(huì)的演講,那么你就會(huì)得出這樣一個(gè)結(jié)論 - Swift可以實(shí)現(xiàn)更快的啟動(dòng)速度,現(xiàn)在卻出現(xiàn)了完全相反的情況。通常情況下二進(jìn)制文件中的動(dòng)態(tài)庫(kù)的數(shù)量將會(huì)直接影響在pre-main中啟動(dòng)時(shí)間,可pre-main和post-main就是由這兩個(gè)決定的。Pre-main發(fā)生在主方法調(diào)用之前,如果動(dòng)態(tài)庫(kù)的數(shù)量太大,花費(fèi)的時(shí)間也就會(huì)更多。

  比如,在一臺(tái)iPhone 6s手機(jī)上面,Swift運(yùn)行時(shí)的庫(kù)需要花費(fèi)250毫秒才能完成他們的動(dòng)作,這也就意味著在這250毫秒期間,你使用Swift也沒(méi)辦法返回,這是一種懶漢現(xiàn)象。

  我們發(fā)現(xiàn)我們所遇到的工具問(wèn)題是由于創(chuàng)建了更多的框架引起的,你框架里的東西越多,那么你的啟動(dòng)速度就越慢。

  解決方案

  可以將所有內(nèi)容重新鏈接到二進(jìn)制文件中,這就是我們采用的方案。 我們構(gòu)建了這些框架,并做了后期處理,將所有的符號(hào)從這些框架中取出,將它們鏈接到靜態(tài)二進(jìn)制文件中,這就是我們解決啟動(dòng)速度慢的方案。

  在企業(yè)證書(shū)方面你也有可能會(huì)遇到問(wèn)題。如果你的設(shè)備具有企業(yè)證書(shū),那么APP時(shí)可能需要花費(fèi)十秒鐘的時(shí)間去進(jìn)行初始化加載,具體得依賴于證書(shū)數(shù)量。

  你可以通過(guò)重鏈接降低時(shí)間,當(dāng)然你也可以通過(guò)做其它的一些調(diào)整來(lái)增加post-main 時(shí)間。

  目前我們正在嘗試使用DTrace來(lái)探測(cè)啟動(dòng)序列中的訪問(wèn)符號(hào)。由于做了重鏈接,所以保證它們是按照正確順序進(jìn)行,這樣就防止在一些老設(shè)備當(dāng)中,不需要將加載大量的頁(yè)面到內(nèi)存中,但是啟動(dòng)過(guò)程中你可以按照需求將某些頁(yè)面給讀到內(nèi)存中。

  令我們感到羞愧的一面

  如果你參加了昨天或者一年前的Swift峰會(huì)的話,你就能感受到了,在演示的過(guò)程中我們遇到了一件真正的麻煩事,那就是編譯速度非常的慢,我們的基礎(chǔ)應(yīng)用需要花費(fèi)15到20分鐘才能完成clean工作。

  對(duì)于這件事情,我們都很擔(dān)心,因此我們?nèi)プ稍兞藞F(tuán)隊(duì)中的每個(gè)人:“這個(gè)問(wèn)題到底有多大”,當(dāng)時(shí)我們是這么問(wèn)的:”根據(jù)以往編程過(guò)程中遇到的問(wèn)題,整體思考一下,在優(yōu)步未來(lái)發(fā)展的過(guò)程中,哪一門(mén)語(yǔ)言你覺(jué)得會(huì)更適合于iOS的開(kāi)發(fā)?”

  這是根據(jù)根據(jù)結(jié)果做的統(tǒng)計(jì)圖,幾乎是一半一半:

Uber 使用 Swift 重寫(xiě) App 的踩坑經(jīng)歷及解決方案

  結(jié)果顯示即使Swift有出錯(cuò)率、無(wú)限索引、編譯速度等各種問(wèn)題,但是他們還是堅(jiān)持會(huì)使用Swift,另一半人則選擇換回Objective-C。

  因此我們又增加了另外一個(gè)問(wèn)題:

  “如果實(shí)現(xiàn)了下面哪一件事或者哪兩件事,那么你就會(huì)選擇Swift,甚至也改變了你對(duì)Swift的認(rèn)知”

  如果僅僅是由于編譯速度的問(wèn)題,實(shí)際上我們是可以解決的。

  編譯速度優(yōu)化

  弄清楚原因以后,我們做的第一件事就是切換回Swift。盡量不要在代碼中使用類(lèi)型判斷,我們研究出了一個(gè)使用SourceKit開(kāi)發(fā)的腳本,這個(gè)腳本可以在后期構(gòu)建所有類(lèi)型,只需更改代碼,使其具有所有類(lèi)型信息就可以了。

  最后,我們開(kāi)始組合文件,我們發(fā)現(xiàn)將我們所有的200個(gè)模型組合成一個(gè)文件以后,可以將編譯時(shí)間從1分35秒減少到只有17秒。 所以我們覺(jué)得“如果繼續(xù)將其它的一切都結(jié)合成一個(gè)文件,那速度豈不是可以更快,這真是太有趣了”。 這樣做的原因是因?yàn)榫幾g器會(huì)對(duì)每個(gè)獨(dú)立的文件進(jìn)行類(lèi)型檢查,所以如果您生成了Swift編譯器的200個(gè)進(jìn)程,則需要檢查所有其他文件的200x,因此將所有內(nèi)容組合成一個(gè)文件可以使其編譯的更快。

  全模塊的優(yōu)化正是我們想要做的。 它將所有的文件都編譯成了一個(gè)文件。 全模塊優(yōu)化問(wèn)題就是優(yōu)化,所以它相當(dāng)慢。 但是如果添加用戶定義的自定義標(biāo)志SWIFT_WHOLE_MODULE_OPTIMIZATION,將其設(shè)置為yes,并將優(yōu)化級(jí)別設(shè)置為none,那么,它將完成全模塊的優(yōu)化,而不進(jìn)行優(yōu)化,它會(huì)超級(jí)快。

  目前我們最大的框架是基于Core Flow做的,它有900個(gè)文件,以前需要四分鐘才能編譯完,現(xiàn)在只需要23秒就可以了。只需要花23秒的時(shí)間就能夠?qū)⒆畲蟮膸?kù)給編譯完,所以即使再也不能進(jìn)行增量編譯了,我也覺(jué)得無(wú)所謂了。大多數(shù)其他目標(biāo)的文件少得多,速度也會(huì)更快。

  Uber正在為Facebook的“Buck”做出貢獻(xiàn),并加入了Swift的支持

  如果整個(gè)模塊的CPU使用率已經(jīng)優(yōu)化到30%以下,那么你就可以考慮做一些其他事情了。如果使用Objective-C語(yǔ)言進(jìn)行開(kāi)發(fā),那我們就必須使用Buck。Buck提供了更好的依賴管理,可靠的增量編譯以及遠(yuǎn)程編譯緩存。它是由Facebook創(chuàng)建,如果在編譯期間出現(xiàn)問(wèn)題你可能就會(huì)關(guān)注它了。我們之前曾分別在objective-c和Android編譯過(guò),最終我們的清理編譯速度提高了4倍,我們的增量編譯快了20倍,因?yàn)樗褂昧诉h(yuǎn)程編譯緩存,所以如果你正在編譯多個(gè)目標(biāo),而另一些人已經(jīng)在其他機(jī)器上編譯了該代碼,那么它將在遠(yuǎn)程編譯緩存中可用,并且只會(huì)使用該文件,它不會(huì)重新編譯任何東西。 在Android上,它的速度更快,像6倍快的清理編譯時(shí)間,而增量版本只是快速的。

  這不是Swift,但我們正在努力,所以我們一直在為Facebook能夠支持Swift而努力,我們現(xiàn)在開(kāi)始嘗試在生成Xcode項(xiàng)目文件的時(shí)候能夠添加Swift支持,我認(rèn)為現(xiàn)在這個(gè)目標(biāo)已經(jīng)幾乎或者接近實(shí)現(xiàn)了,我們已經(jīng)在內(nèi)部開(kāi)始這么做了,現(xiàn)在已經(jīng)可以根據(jù)文件夾結(jié)構(gòu)是用Buck來(lái)生成工程文件了。

  接下來(lái),我們正在為實(shí)現(xiàn)Buck編譯添加Swift支持而努力,這么做的目的就是以后可以使用Buck編譯我們的應(yīng)用程序。 最終我們還想要去研究如何將已經(jīng)添加到Buck的Swift支持整合到Xcode中,如果研究成功的話,那么當(dāng)你打cmd + B,它不會(huì)使用Xcode編譯,而是會(huì)使用Buck進(jìn)行編譯。

  如果使用Buck的話,現(xiàn)在6分鐘的編譯時(shí)間,以后可能會(huì)減少到的2分鐘甚至更短。 這將從本質(zhì)上解決Swift編譯時(shí)間的問(wèn)題。 這一切都可以按照Buck repo進(jìn)行,您最終會(huì)看到Swift支持也會(huì)加進(jìn)來(lái)的。

  原文:Swift with a hundred engineers

  翻譯:Vincent

您還未登錄,請(qǐng)先登錄

熱門(mén)帖子

最新帖子

?