隨著開(kāi)發(fā)的不斷進(jìn)行卤材,我們的項(xiàng)目總會(huì)變得越來(lái)越大狸窘,而過(guò)大的占用用戶(hù)的內(nèi)存空間會(huì)對(duì)用戶(hù)的留存造成一定的影響橡娄,所以我們總是需要找到方案來(lái)減小我們的包大小立美。在我們努力的同時(shí)蘋(píng)果也在為此努力著,下文的第一部分主要介紹的就是官方文檔和個(gè)人經(jīng)驗(yàn)總結(jié)出的一些關(guān)于包瘦身的方案隘竭。此外項(xiàng)目變大后塘秦,我們?cè)陂_(kāi)發(fā)時(shí)每次啟動(dòng)程序的編譯時(shí)間都會(huì)變長(zhǎng),這對(duì)于開(kāi)發(fā)者而言是效率極低的一件事动看,文章的第二部分主要介紹如何在編譯速度的角度去優(yōu)化程序尊剔。
項(xiàng)目瘦身
-
切面(Slicing)
這一功能是蘋(píng)果在 iOS 9 、watchOS 2 菱皆、tvOS 中推出的新功能须误,不需要我們進(jìn)行任何的設(shè)置就可以完成,這個(gè)功能的主要作用在于對(duì)于不同的設(shè)備可以下發(fā)根據(jù)當(dāng)前設(shè)備的CPU架構(gòu)的可執(zhí)行文件和資源文件仇轻。所以當(dāng)用戶(hù)在下載APP的時(shí)候就會(huì)進(jìn)行匹配京痢,而不會(huì)向之前一樣下載針對(duì)所有設(shè)備的架構(gòu)文件了,這樣就變相的幫助我們減小了包體積篷店。
-
Bitcode
這一功能同樣是在 iOS 9 之后推出祭椰,可以在 Xcode 7 以上版本中在 Build Setting -> Enable Bitcode ( ENABLE_BITCODE ) 先完成對(duì)應(yīng)的設(shè)置。這樣做的好處在于官方會(huì)自動(dòng)的幫我們?nèi)プ鲆恍﹥?yōu)化疲陕,查看了一些國(guó)外的文章大致的猜想是蘋(píng)果在設(shè)備安裝應(yīng)用的時(shí)候方淤,會(huì)根據(jù)設(shè)備的 CPU 架構(gòu)自動(dòng)的去下發(fā)與架構(gòu)相匹配的一份二進(jìn)制文件,而生成的其它 CPU 架構(gòu)的二進(jìn)制文件則不被下發(fā)蹄殃。這樣就可以讓我們的包體積大大減小携茂,我們的項(xiàng)目可能會(huì)在 iphone4s 、 iphones 5 诅岩、iphone 6 上進(jìn)行使用讳苦。如果我們用 iphone6 去下載,那么只會(huì)給我們一份 arm 64 架構(gòu)下編譯文件按厘,而不會(huì)在下載 armv 7 和 armv 7s下的編譯文件医吊。這樣對(duì)我們包體積的優(yōu)化還是很有必要的钱慢。
Bitcode 相關(guān)文章鏈接(自備梯子) -
資源文件下載
我們一般在開(kāi)發(fā)過(guò)程中遇到的一些界面UI圖片都是放在本地的Asserts文件夾中的逮京,所以隨著項(xiàng)目的擴(kuò)充,我們可能會(huì)有非常多的資源文件束莫,而此時(shí)包體積會(huì)變得非常的大懒棉。為了解決這一問(wèn)題草描,蘋(píng)果在 iOS 9 中同樣提出了對(duì)應(yīng)的解決方案。我們可以把一些不常用的界面的 UI 存儲(chǔ)在蘋(píng)果的服務(wù)器上策严,第一次進(jìn)入界面的時(shí)候穗慕,會(huì)去服務(wù)器加載相關(guān)的圖片,然后將圖片下載到本地妻导,下次進(jìn)入該頁(yè)面會(huì)從本地讀取資源文件逛绵。這樣的方案聽(tīng)起來(lái)為我們解決了包體積過(guò)大的問(wèn)題。
但是這樣的解決方案有如下的缺陷倔韭。
這一項(xiàng)功能也是在 iOS 9 之后的設(shè)備上才能夠被使用术浪,也就是說(shuō)我們的項(xiàng)目如果支持 iOS 8 及以下的設(shè)備還是沒(méi)有辦法完成。
這一功能下載的資源文件雖然存儲(chǔ)在本地寿酌,但是如果用戶(hù)的設(shè)備磁盤(pán)空間不足的時(shí)候胰苏,系統(tǒng)會(huì)優(yōu)先清空這一部分內(nèi)存,也就是說(shuō)用戶(hù)可能對(duì)于這些資源需要下載多次醇疼。
因?yàn)槭菑奶O(píng)果服務(wù)器上拉取資源文件硕并,所以肯定要考慮網(wǎng)絡(luò)環(huán)境的問(wèn)題,如果網(wǎng)絡(luò)環(huán)境不好的情況下秧荆,這樣的方法對(duì)于用戶(hù)體驗(yàn)是不友好的倔毙。
-
實(shí)戰(zhàn)方案
其實(shí)相比于我們的代碼,比較占內(nèi)存的還是資源文件乙濒,所以除了優(yōu)化本地代碼結(jié)構(gòu)普监,更好的封裝刪除無(wú)用代碼之外,最主要的優(yōu)化還是對(duì)于資源文件的優(yōu)化
首先我們可以和設(shè)計(jì)商量琉兜,在保證圖片高保真的情況下凯正,將圖片大小盡力的去壓縮。我們項(xiàng)目中曾有1000k+ 的大圖后來(lái)壓縮到 200k+ 左右豌蟋,所以這樣的方案還是很有用的廊散。mac 下也有專(zhuān)門(mén)的軟件,因?yàn)闆](méi)有設(shè)計(jì)在壓縮上專(zhuān)業(yè)梧疲,所以后來(lái)我就不再用了允睹,有興趣的小伙伴可以去搜一下。
此外幌氮,我們可以去寫(xiě)一個(gè)腳本缭受,查找項(xiàng)目中沒(méi)有被使用的圖片。還可以用比較笨的方法去找命名不同但完全一致的圖片该互。同時(shí)在日常開(kāi)發(fā)中米者,我們可能因?yàn)閁I尺寸的不同而導(dǎo)入同樣的圖片兩次,其實(shí)這完全都是沒(méi)有必要的,因?yàn)橹粚?dǎo)入最大的尺寸圖片按照對(duì)應(yīng)比例進(jìn)行展示蔓搞,其實(shí)展示的都是高保真圖片胰丁。
最后其實(shí)是開(kāi)發(fā)中的技巧,就是可能一個(gè)按鈕在不一樣的狀態(tài)下顏色是不一樣的喂分,但是按鈕的樣式完全相同锦庸,此時(shí)我們可能會(huì)導(dǎo)入兩套 UI , 其實(shí)這種情況下,我們完全可以只用一套沒(méi)有顏色的UI 蒲祈,然后通過(guò)代碼完成圖片顏色的繪制即可甘萧。
如果還有其它較好的解決方案,還希望小伙伴給我留言梆掸。此外關(guān)于前三部分的介紹幔嗦,也可以查看相關(guān)的文檔。文檔地址
編譯速度優(yōu)化
隨著項(xiàng)目一次次的功能的增加沥潭,各種框架的引入邀泉,我們的項(xiàng)目變大的同時(shí),我們每次在模擬器或者真機(jī)上運(yùn)行的時(shí)候钝鸽,執(zhí)行緩慢的問(wèn)題對(duì)我們?nèi)粘i_(kāi)發(fā)的效率造成了很大的影響汇恤,針對(duì)這樣的問(wèn)題,我們就要對(duì)項(xiàng)目進(jìn)行優(yōu)化拔恰,加快編譯速度因谎。這時(shí)就要了解程序的編譯原理。對(duì)于編譯的原理颜懊,我覺(jué)得《程序是如何跑起來(lái)的》一書(shū)财岔,對(duì)于這一點(diǎn)的介紹淺顯易懂,有興趣的小伙伴可以買(mǎi)一本河爹,讀一下知道編譯器是如何進(jìn)行編譯的也就能找到一些加快編譯速度的方案匠璧。
-
正確的使用 .pch文件
在 Xcode 6 之前創(chuàng)建一個(gè)新的工程是會(huì)自帶一個(gè) .pch 文件的,但是后來(lái)蘋(píng)果把這個(gè)自帶的功能刪除了咸这,就是因?yàn)橛泻芏嗟拈_(kāi)發(fā)者不能正確的使用它夷恍。導(dǎo)致程序的編譯速度變慢。所以這里會(huì)介紹介紹如何正確的進(jìn)行使用媳维。其實(shí) .pch 文件正確使用是可以加快程序的編譯速度的酿雪。
- 首先,在 .pch 文件中不要導(dǎo)入宏定義侄刽,因?yàn)槲覀兌贾篮甓x是去匹配的機(jī)制指黎,如果全局匹配,無(wú)疑很耗費(fèi)時(shí)間州丹,所以在 .pch 文件中一定不要做全局的宏定義醋安。將宏定義最好寫(xiě)道每一部分的頭文件中。
其次,.pch 文件中主要進(jìn)行加載的是一些比較大的文件茬故,但是如果是我們自己寫(xiě)的比較大的文件盖灸,也不要加到 .pch 文件中去蚁鳖,因?yàn)槿绻坏┐a被更改磺芭,就會(huì)出現(xiàn)很奇怪的問(wèn)題。而且加載到 .pch 文件中的文件代碼在多個(gè)項(xiàng)目中的可復(fù)用性不好醉箕。也會(huì)對(duì)編譯速度造成一定的影響钾腺。 比較建議的是可以在這個(gè)文件中導(dǎo)入 Foudation 、UIKit 這樣常用的系統(tǒng)級(jí)框架
最后讥裤,可能會(huì)有小伙伴有這樣的經(jīng)歷放棒,就是像MBProgressHud 類(lèi)似在全局都會(huì)經(jīng)常使用到的類(lèi)是不是可以放到 .pch 文件中呢,少量的幾個(gè)不大的文件導(dǎo)入還可以己英,多了對(duì)于編譯速度本身是不好的间螟。
與此相關(guān)的文章可以參考 stackoverflow 相關(guān)回答
-
正確到 import 操作
在我們?nèi)粘5拈_(kāi)發(fā)中B類(lèi)可能用到A類(lèi),有時(shí)候可能需要將A類(lèi)在 .h 文件中聲明成一個(gè)屬性损肛,這個(gè)時(shí)候可能有人就會(huì)在 .h 文件中直接 #import “AClass” 這樣的做法就是不合理的厢破,因?yàn)閷?duì)于編譯時(shí)而言完全不需要再這個(gè)類(lèi)的全部信息編譯進(jìn)來(lái),只需要知道該類(lèi)被引入即可治拿,所以此時(shí)使用 @class AClass 摩泪;更加合理,此外如果兩個(gè)類(lèi)互相引用對(duì)方劫谅,頭文件中使用 @class 的方案不會(huì)報(bào)編譯錯(cuò)誤见坑。另外攝像一下如果引用鏈如下 A -> B -> C -> D... 這樣一直向下,那么這個(gè)時(shí)候捏检,編譯鏈條中的最后一個(gè)類(lèi)發(fā)生更改荞驴,那么整個(gè)從A開(kāi)始相關(guān)的類(lèi)也就全部需要重新編譯,那么編譯時(shí)間編程也就變成了必然贯城,所以一定注意 #import 的正確使用戴尸。
-
打包靜態(tài)鏈接庫(kù)
最近發(fā)現(xiàn)周?chē)笥训墓径荚谶M(jìn)行組件化開(kāi)發(fā),然后將每一個(gè)組件打包成 pod 冤狡,而每一個(gè) pod 中都是一個(gè) .a 的靜態(tài)鏈接庫(kù)孙蒙。每個(gè)部門(mén)或者小組只要負(fù)責(zé)維護(hù)自己的 .a 庫(kù)即可,與其它團(tuán)隊(duì)沒(méi)有太多的影響悲雳。也不會(huì)再出現(xiàn)提交代碼各種沖突的問(wèn)題挎峦,這一點(diǎn)上真的很贊。但這需要很好地架構(gòu)體系合瓢,因?yàn)樗皆虿蛔稣归_(kāi)坦胶。只是討論 .a 文件的作用。
我們?nèi)粘i_(kāi)發(fā)中可以將我們不會(huì)修改的三方庫(kù)或者已經(jīng)成熟基本不會(huì)改變的業(yè)務(wù)模塊打包成 .a 的靜態(tài)鏈接庫(kù)。因?yàn)閷?duì)應(yīng)文件打包生成靜態(tài)鏈接庫(kù)之后顿苇,生成的就是對(duì)應(yīng) CPU 架構(gòu)下的二進(jìn)制文件峭咒,在程序編譯時(shí)就不會(huì)在占用編譯的時(shí)間,而是在運(yùn)行時(shí)纪岁,直接連接寫(xiě)入內(nèi)存凑队,所以可以起到優(yōu)化編譯速度的作用。當(dāng)然打包 .a 靜態(tài)庫(kù)可能就會(huì)涉及到 release 和 debug 版本 幔翰,device 和 simulator 兼容性的問(wèn)題漩氨,這一點(diǎn)網(wǎng)上有很多相關(guān)的資料可以進(jìn)行參考。
以上就是在編譯速度上進(jìn)行優(yōu)化的一些個(gè)人建議遗增。
文中出現(xiàn)的錯(cuò)誤煩請(qǐng)您指出叫惊,我會(huì)第一時(shí)間進(jìn)行修改。