編譯選項
1.編譯器優(yōu)化級別
Build Settings->Optimization Level有幾個編譯優(yōu)化選項茂翔,release版應該選擇Fastest, Smalllest挠蛉,這個選項會開啟那些不增加代碼大小的全部優(yōu)化腊尚,并讓可執(zhí)行文件盡可能小。
2.去除符號信息
Strip Linked Product / Deployment Postprocessing / Symbols Hidden by Default 在release版本應該設為yes腊脱,可以去除不必要的調(diào)試符號祝谚。Symbols Hidden by Default會把所有符號都定義成”private extern”悠瞬,詳細信息見官方文檔。
這些選項目前都是XCode里release的默認選項宵睦,但舊版XCode生成的項目可能不是记罚,可以檢查一下。其他優(yōu)化還可以參考官方文檔—CodeFootprint.pdf
第三方庫統(tǒng)計
項目里會引入很多第三方靜態(tài)庫壳嚎,如果能知道這些第三方庫在可執(zhí)行文件里占用的大小桐智,就可以評估是否值得去找替代方案去掉這個第三方庫。我們可以從linkmap中統(tǒng)計出這個信息烟馅,對此寫了個node.js腳本说庭,可以通過linkmap統(tǒng)計每個.o目標文件占用的體積和每個.a靜態(tài)庫占用的體積,詳見這里(需翻墻)郑趁。
無用代碼
在項目里新建一個類刊驴,給它添加幾個方法,但不要在任何地方import它寡润,build完項目后觀察linkmap捆憎,你會發(fā)現(xiàn)這個類還是被編譯進可執(zhí)行文件了。
在C++中沒有被使用到的類和方法編譯器都會優(yōu)化掉梭纹,不會編進最終的可執(zhí)行文件躲惰,但object-c不一樣,因為object-c的動態(tài)特性变抽,它可以通過類和方法名反射獲得這個類和方法進行調(diào)用礁扮,所以就算在代碼里某個類沒被使用到知举,編譯器也沒法保證這個類不會在運行時通過反射去調(diào)用,所以只要是在項目里的文件太伊,無論是否又被使用到都會被編譯進可執(zhí)行文件雇锡。
對此我們可以通過腳本,遍歷整個項目的文件僚焦,找出所有沒有被引用的類文件和沒有被調(diào)用的方法锰提,在保證沒有其他地方動態(tài)調(diào)用的情況下把它們?nèi)サ簟H绻麄€項目歷時很長芳悲,歷時代碼遺留較多立肘,這個清理對可執(zhí)行文件省出的空間還是挺可觀的。
類/方法名長度
觀察linkmap可以發(fā)現(xiàn)每個類和方法名都在__cstring段里都存了相應的字符串值名扛,所以類和方法名的長短也是對可執(zhí)行文件大小是有影響的谅年,原因還是object-c的動態(tài)特性,因為需要通過類/方法名反射找到這個類/方法進行調(diào)用肮韧,object-c對象模型會把類/方法名字符串都保存下來融蹂。
對此我們可以考慮在編譯前把所有類和方法名進行混淆,跟壓縮js一樣弄企,把長名字替換成短名字超燃,這樣做的好處除了縮小體積外,還對安全性有很大提升拘领,別人拿到可執(zhí)行文件對它class-dump出來的結(jié)果都是混淆后的類和方法名意乓,就無法從類和方法名中猜出某個方法是做什么的,就難以掛鉤子進行hack约素。不過這樣做有個缺點届良,就是crash堆棧反解出來的堆棧方法名會是混淆后的,需要再加一層混淆->原名的轉(zhuǎn)換圣猎,實現(xiàn)和使用成本有點高伙窃。
實際上這部分占用的長度比較小,中型項目也就幾百K样漆,對安全性要求高的情況可以試試。
冗余字符串
代碼上定義的所有靜態(tài)字符串都會記錄在在可執(zhí)行文件的__cstring段晦闰,如果項目里Log非常多放祟,這個空間占用也是非常可觀的呻右,也有幾十幾百K的跪妥,可以考慮清理所有冗余的字符串。另外如果有特別長的字符串声滥,建議抽離保存成靜態(tài)文件眉撵,因為AppStore對可執(zhí)行文件加密導致壓縮率低侦香,特別長的字符串抽離成靜態(tài)資源文件后壓縮率會比在可執(zhí)行文件里高很多。