當(dāng)我們談?wù)搃OS瘦身的時候,我們到底在談?wù)撔┦裁?/h2>

不斷的開發(fā)迭代,產(chǎn)品經(jīng)理不斷的添加需求,引入的資源文件幾乎是只加不減,猛然回首,iOS包已經(jīng)100多m,看來iOS瘦身迫在眉睫?。。。?!

iOS瘦身的好處


我們先來討論 iOS瘦身的好處,正所謂知其然知其所以然。iOS瘦身有哪些好處?

1. However, consider download times when determining your app’s size. Minimize the file’s size as much as possible, keeping in mind that there is a 100 MB limit for over-the-air downloads. Abnormally large build files are usually the result of storing data, such as images, inside the compiled binary itself instead of as a resource inside your app bundle. If you are compiling an image or large dataset into your binary, it would be best to split this data out into a resource that is loaded dynamically by your app.

1.首先對于新用戶當(dāng)?shù)谝话惭b你的iOS程序時,需要下載完整的一個.ipa文件。(注意不同于升級),相同環(huán)境下iOS包越小用戶的下載時間越少,這一點(diǎn)對于用戶體驗來說至關(guān)重要,特別是有些情況apple store訪問不太順利,用戶下載你的iOS包肯定是迫切想了解使用你的產(chǎn)品,如果用戶等半天(等待對于用戶總是漫長的),用戶會煩躁帶著這種心情去了解你的產(chǎn)品,第一印象肯定不爽!

2.回想起來你的app第一個版本,有可能才10幾m,才一年多的時間,你的app已經(jīng)變成100m了,然而產(chǎn)品業(yè)務(wù)需求是不斷迭代的,如果不加以控制,后面只會越來越大!

3.可能絕大部分的原因,你的產(chǎn)品并非是強(qiáng)勢app(比如支付寶,qq,百度)所以你也就不能隨便耍流氓,用戶手機(jī)的存儲空間是有限的(特別是那些16g的iPhone),除了那些強(qiáng)勢app,你必須要在剩余不多的空間,爭取用戶不會刪除你的app(特別是那些工具類型app)!

4.less is more ,對于代碼和那些資源文件也是如此,無用的代碼和資源文件越多,就導(dǎo)致項目冗余越大,維護(hù)也越麻煩,比如很可能同一張圖片有好幾個不同命名,如果要改圖片了就要全部更換 !

知道了瘦身的好處接下來,我們就談?wù)撘幌耰OS該怎么瘦身

iOS該怎么瘦身 ?


在做任何相關(guān)優(yōu)化之前,我們需要做一些權(quán)衡。通過權(quán)衡,可以知道把優(yōu)化的重點(diǎn)集中在什么地方。我們上文提到,當(dāng)?shù)谝话惭biOS程序時,需要下載完整的一個.ipa文件。實際上.ipa文件就是一個.zip結(jié)構(gòu)。簡單的將后綴為.ipa文件修改為.zip,然后利用Finder將其解壓出來。右鍵單擊解壓出來的.app bundle,選擇顯示包內(nèi)容,以查看里面的資源文件。通過該方法我們可以看到哪些文件占的空間最大。記住:.app bundle是經(jīng)過壓縮的,并且有些文件的壓縮效果要比別的文件好,所以壓縮后的效果才是才是最重要的。不過一般情況下在壓縮前最大的文件,在壓縮后依舊是最大的文件。

而這些資源文件(包括圖片、聲音以及其它配置文件)通常占了ipa 很大部分,所以我首先針對資源文件優(yōu)化。

(1).資源文件瘦身

a.刪除無用的圖片資源

一個項目開發(fā)的越久,添加的功能模塊就越多,相應(yīng)的,也會慢慢引入更多的圖片資源。但是在移除一些不再使用的模塊時,開發(fā)者往往不會將對應(yīng)的圖片資源一起刪除,因為圖片資源和源碼是分離的,長久以來,項目中就會出現(xiàn)大量沒有使用的圖片資源。刪除無用的資源一般來說 能減掉個2~3MB。 這個時候就要使用工具自動迅速找出工程中所有沒被使用的資源文件嘍(想想就知道了 ,用手工得多慢多累?。?,工欲善其事,必先利其器。

我首先推薦的是https://github.com/tinymind/LSUnusedResources? 整個過程非常的快, 比shell腳本不知道方便到哪里去了, 為了照顧那些懶癌癥患者 我把使用方法也貼出來

使用方法如下

1.點(diǎn)擊 Browse.. 選擇一個文件夾;

2.點(diǎn)擊 Search 開始搜索;

3.等待片刻即可看到結(jié)果;

4.選中某些行,然后點(diǎn)擊 Delete 可以直接刪除資源

第二種方法就是你也可以用萬能的腳本 https://github.com/examplecode/unused-image/blob/master/unused-image.sh? ?&&? http://stackoverflow.com/questions/6113243/how-to-find-unused-images-in-an-xcode-project/6113449#6113449

b.對資源壓縮

首先 盡量使用8-bit的PNG圖片,比32-bit的圖片能減少4倍的壓縮率。由于8-bit的圖片支持最多256種不同的顏色,所以8-bit的圖片一般只應(yīng)該用于一小部分的顏色圖片。例如灰度圖片最好使用8-bit。然后并不能事事都如意, 設(shè)計師提供的圖片資源往往都是直接從sketch中剪切后的資源,大小非常大,這個時候就需要對png進(jìn)行無損壓縮,假設(shè)我們的項目中有30M的圖片,然后將它們有損壓縮到80%的質(zhì)量,那么就可以減掉6MB左右。可以使用以下兩種方法進(jìn)行圖片的壓縮:用的是ImageOptim工具和compress命令(具體怎么使用我不想寫了)。但是并不建議對資源做有損壓縮,因為有損壓縮通常壓縮后效果不盡人意需要設(shè)計一個個檢查。

c. BitCode

首先我們來介紹一下? BitCode 是啥?

Bitcode is an intermediate representation of a compiled program. Apps

you upload to iTunes Connect that contain bitcode will be compiled and

linked on the App Store. Including bitcode will allow Apple to

re-optimize your app binary in the future without the need to submit a

new version of your app to the store.

說的是bitcode是被編譯程序的一種中間形式的代碼。包含bitcode配置的程序?qū)贏pp store上被編譯和鏈接。bitcode允許蘋果在后期重新優(yōu)化我們程序的二進(jìn)制文件,而不需要我們重新提交一個新的版本到App store上。呀,真有這么高級?

LLVM是目前蘋果采用的編譯器工具鏈,Bitcode是LLVM編譯器的中間代碼的一種編碼,LLVM的前端可以理解為C/C++/OC/Swift等編程語言,LLVM的后端可以理解為各個芯片平臺上的匯編指令或者可執(zhí)行機(jī)器指令數(shù)據(jù),那么,BitCode就是位于這兩者直接的中間碼. LLVM的編譯工作原理是前端負(fù)責(zé)把項目程序源代碼翻譯成Bitcode中間碼,然后再根據(jù)不同目標(biāo)機(jī)器芯片平臺轉(zhuǎn)換為相應(yīng)的匯編指令以及翻譯為機(jī)器碼.這樣設(shè)計就可以讓LLVM成為了一個編譯器架構(gòu),可以輕而易舉的在LLVM架構(gòu)之上發(fā)明新的語言(前端),以及在LLVM架構(gòu)下面支持新的CPU(后端)指令輸出,雖然Bitcode僅僅只是一個中間碼不能在任何平臺上運(yùn)行,但是它可以轉(zhuǎn)化為任何被支持的CPU架構(gòu),包括現(xiàn)在還沒被發(fā)明的CPU架構(gòu),也就是說現(xiàn)在打開Bitcode功能提交一個App到應(yīng)用商店,以后如果蘋果新出了一款手機(jī)并CPU也是全新設(shè)計的,在蘋果后臺服務(wù)器一樣可以從這個App的Bitcode開始編譯轉(zhuǎn)化為新CPU上的可執(zhí)行程序,可供新手機(jī)用戶下載運(yùn)行這個App.

扯了這么多 ,推出Bitcode的好處是啥? 跟iOS瘦身啥關(guān)系?之前打包,可以運(yùn)行在各個不同型號的iOS設(shè)備上,是因為在打包的時候,蘋果幫我們把a(bǔ)pp在各型號設(shè)備上運(yùn)行所需要的“東西”一并全部打到包里了。假設(shè)我們在打包的時候,只把要運(yùn)行的設(shè)備所需的“東西”打到包里,而不需要其他型號運(yùn)行所需要的“東西”,這樣不就達(dá)到減小ipa大小的目的了么?BitCode就是來完成這個任務(wù)的中間件。

d.正確導(dǎo)入圖片的姿勢


圖片的導(dǎo)入方式有如下幾種:

1.加入到Assets.xcassets中

只支持png格式的圖片

圖片只支持[UIImage imageNamed]的方式實例化,但是不能從Bundle中加載

在編譯時,Images.xcassets中的所有文件會被打包為Assets.car的文件

2.CreateGroup

黃色文件夾圖標(biāo);Xcode中分文件夾,Bundle中所有所在都在同一個文件夾下,因此,不能出現(xiàn)文件重名的情況

可以直接使用[NSBundle mainBundle]作為資源路徑,效率高!

可以使用[UIImage imageNamed:]加載圖像

3.CreateFolderRefences

藍(lán)色文件夾;Xcode中分文件夾,Bundle中同樣分文件夾,因此,可以出現(xiàn)文件重名的情況

需要在[NSBundle mainBundle]的基礎(chǔ)上拼接實際的路徑,效率較差

不能使用[UIImage imageNamed:]加載圖

4.PDFs矢量圖(Xcode6+)

5.Bundle(包)中的圖片素材

那這不同的導(dǎo)入方式,會對打出的包的大小有影響么?

經(jīng)過測試得知:CreateGroup、CreateFolderRefences兩種方式打出來的包,圖片都會直接放在.app文件中,所以打包前后,圖片的大小不會改變

而加入到Assets.xcassets中的方法則不同,打包后,在.app中會生成Assets.car文件來存儲Assets.xcassets中的圖片,并且文件大小方面也大大降低

所以,使用Assets.xcassets來管理圖片也可以達(dá)到ipa瘦身的效果~~

話說PDFs矢量圖呢 ,利用矢量圖能不能幫助iOS App減少整體空間?

iOS對矢量圖的支持其實只是一種方便開發(fā)者的選擇, 本質(zhì)上在XCode編譯的階段矢量圖會自動生成對應(yīng)Target的@1x,@2x和@3x的png格式圖像。在iOS實際運(yùn)行中使用的圖片實際上已經(jīng)是png格式的圖片了~

用簡單粗暴的實驗來對比說明, 步驟如下:

使用pdf原始文件編譯生成通用IPA

從生成的IPA文件中提取Asset.car文件

利用iOS Image Extractor提取Asset.car文件

將提取出來的@1x、@2x、@3x放置回工程, 并刪除原始pdf中重新編譯

對比步驟1生成的car文件和步驟4生成的car文件大小

結(jié)果如下:

在iOS8.3以下, 相同壓縮比例的條件下, 矢量圖是無法幫助App減少空間。但是在iOS8.3以上, 利用xcassets可以避免多余的資源圖片下載, 只下載對應(yīng)的倍率的圖片。因此, 嚴(yán)格意義下, 利用矢量圖并不能幫助App節(jié)省空間(其實跟用Assets.xcassets的方式效果差不多)。但是pdf矢量圖使用起來非常的方便, 建議使用。iOS本質(zhì)上并不支持矢量圖, 但是在編譯階段會將矢量圖轉(zhuǎn)化成目標(biāo)設(shè)備對應(yīng)的尺寸圖, 同時會利用xcassets的特性在iOS8.3以上設(shè)備下支持部分資源下載, 帶到包瘦身的效果。每次都要讓UI給多個尺寸的圖, 肯定沒有給一張方便吧? 當(dāng)然, 前提是UI的童鞋是基于矢量圖工具制作的圖片的前提下~

簡單的iOS瘦身技巧講完了 ,我們來點(diǎn)兒稍微高級的,畢竟步子要一步一步走,邁步太大容易扯著蛋


(2).代碼級別的優(yōu)化

比如 在項目里新建一個類,給它添加幾個方法,但不要在任何地方import它,build完項目后觀察linkmap,你會發(fā)現(xiàn)這個類還是被編譯進(jìn)可執(zhí)行文件了。這是因為object-c的runtime 性質(zhì),按C++的經(jīng)驗,沒有被使用到的類和方法編譯器都會優(yōu)化掉,不會編進(jìn)最終的可執(zhí)行文件,object-c不一樣,因為object-c的動態(tài)特性,它可以通過類和方法名反射獲得這個類和方法進(jìn)行調(diào)用,所以就算在代碼里某個類沒被使用到,編譯器也沒法保證這個類不會在運(yùn)行時通過反射去調(diào)用,所以只要是在項目里的文件,無論是否又被使用到都會被編譯進(jìn)可執(zhí)行文件。又比如我們的項目里會引入很多第三方靜態(tài)庫,如果能知道這些第三方庫在可執(zhí)行文件里占用的大小,就可以評估是否值得去找替代方案去掉這個第三方庫。

這個時候就要介紹一下LinkMap了,LinkMap文件是Xcode產(chǎn)生可執(zhí)行文件的同時生成的鏈接信息,用來描述可執(zhí)行文件的構(gòu)造成分,包括代碼段(__TEXT)和數(shù)據(jù)段(__DATA)的分布情況。比如說可執(zhí)行文件的構(gòu)成是怎樣,里面的內(nèi)容都是些什么,?

1、使用LinkMap文件對可執(zhí)行文件安裝包進(jìn)行分析

在xcode的設(shè)置中 Project->Build Settings->Write Link Map File為YES,并設(shè)置Path to Link Map File,build完后就可以在設(shè)置的路徑看到LinkMap文件了

注意:此時最好使用真機(jī)進(jìn)行編譯,不然可能無法找到我們想要的文件。

在以下目錄可以看到LinkMap文件,如下:

/Users/chenxintao/Library/Developer/Xcode/DerivedData/AppName-fnpgyspdoyxnotbpoliocmwypkff/Build/Intermediates/AppName.build/Debug-iphoneos/AppName.build/AppName-LinkMap-normal-arm64.txt

LinkMap文件主要分為以下三部分:

1.1 Object files

整個可執(zhí)行文件里包含的所有.O文件,前面的數(shù)字是這個.o文件的序號。樣式如下:

# Object files:

[0] linker synthesized

[1]/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/usr/lib/crt1.o

[2]/Users/bang/Library/Developer/Xcode/DerivedData/yishu-eyzgphknrrzpevagadjtwpzzeqag/Build/Intermediates/yishu.build/Debug-iphonesimulator/yishu.build/Objects-normal/i386/TKPFileInfo.o

...

[280] /Users/bang/Downloads/yishu/yishu/Classes/lib/UMeng/MobClick/libMobClickLibrary.a(UMANJob.o)

[281] /Users/bang/Downloads/yishu/yishu/Classes/lib/UMeng/MobClick/libMobClickLibrary.a(UMANWorker.o)

[282] /Users/bang/Downloads/yishu/yishu/Classes/lib/UMeng/MobClick/libMobClickLibrary.a(MobClick.o)

[283] /Users/bang/Downloads/yishu/yishu/Classes/lib/UMeng/MobClick/libMobClickLibrary.a(UMANLaunch.o)

前面中括號里的是這個文件的編號,后面會用到,像項目里引用到靜態(tài)鏈接庫libMobClickLibrary.a里的目標(biāo)文件都會在這里列出來。

1.2 Sections

接著是一個段表,描述各個段在最后編譯成的可執(zhí)行文件中的偏移位置及大小,包括了代碼段(__TEXT,保存程序代碼段編譯后的機(jī)器碼)和數(shù)據(jù)段(__DATA,保存變量值)。樣式如下:

# Sections:

# Address? Size? ? Segment? Section

0x00002740 0x00273890 __TEXT __text

0x00275FD0 0x00000ADA __TEXT __symbol_stub

0x00276AAC 0x00001222 __TEXT __stub_helper

0x00277CCE 0x00019D9E __TEXT __objc_methname

0x00291A70 0x00012847 __TEXT __cstring

0x002A42B7 0x00001FC1 __TEXT __objc_classname

0x002A6278 0x000046A7 __TEXT __objc_methtype

0x002AA920 0x000061CE __TEXT __ustring

0x002B0AF0 0x00000764 __TEXT __const

0x002B1254 0x000028B8 __TEXT __gcc_except_tab

0x002B3B0C 0x00004EBC __TEXT __unwind_info

0x002B89C8 0x0003662C __TEXT __eh_frame

0x002EF000 0x00000014 __DATA __program_vars

0x002EF014 0x00000284 __DATA __nl_symbol_ptr

0x002EF298 0x0000073C __DATA __la_symbol_ptr

0x002EF9E0 0x000030A4 __DATA __const

0x002F2A84 0x00000590 __DATA __objc_classlist

0x002F3014 0x0000000C __DATA __objc_nlclslist

0x002F3020 0x0000006C __DATA __objc_catlist

0x002F308C 0x000000D8 __DATA __objc_protolist

0x002F3164 0x00000008 __DATA __objc_imageinfo

0x002F3170 0x0002BC80 __DATA __objc_const

0x0031EDF0 0x00003A30 __DATA __objc_selrefs

0x00322820 0x00000014 __DATA __objc_protorefs

0x00322834 0x000006B8 __DATA __objc_classrefs

0x00322EEC 0x00000394 __DATA __objc_superrefs

0x00323280 0x000037C8 __DATA __objc_data

0x00326A48 0x000096D0 __DATA __cfstring

0x00330118 0x00001424 __DATA __objc_ivar

0x00331540 0x00006080 __DATA __data

0x003375C0 0x0000001C __DATA __common

0x003375E0 0x000018E8 __DATA __bss

1.3 Symbols

可執(zhí)行文件中各種symbol的大小,包括各個symbol的起始地址,占用大小,來自哪一個.o文件(使用之前提到的.o文件的序號)。樣式如下:

# Address ? Size ?File ? ?Name

0x00002740 0x0000003E [ 1] start

0x00002780 0x00000400 [ 2] +[TKPFileInfo parseWithDictionary:]

0x00002B80 0x00000030 [ 2] -[TKPFileInfo fileID]

...

計算某個.o文件在最終安裝包中占用的大小,主要是解析Object files和Symbols兩個部分,從Object files讀取出每個.o文件名和對應(yīng)的序號,然后對Symbols中序號相同的文件的Size字段相加,即可得到每個.o文件在最終包的大小。 同樣首列是數(shù)據(jù)在文件的偏移地址,第二列是占用大小,第三列是所屬文件序號,對應(yīng)上述Object files列表,最后是名字。例如第二行代表了文件序號為2(反查上面就是TKPFileInfo.o)的parseWithDictionary方法占用了1000byte大小。

我們看到在這個里面除了可以看到DATA字段與TEXT字段的大小外,它還會列出所有類對象下的成員函數(shù)與類函數(shù)。其實這點(diǎn)很重要,因為這樣我們就可以知道工程中所有實現(xiàn)的函數(shù)了。通過相應(yīng)的正則表達(dá)式,我們就可以提取出函數(shù)內(nèi)容,其正則表達(dá)式為[+|-][.+\s(.+)],然后我們通過另外一個強(qiáng)大的反編譯工具otool,可以提取出工程中所使用的函數(shù)列表(Used Selectors All)。

先說那什么是otool呢?

Otool可以提取并顯示ios下目標(biāo)文件的相關(guān)信息,包括頭部,加載命令,各個段,共享庫,動態(tài)庫等等。它擁有大量的命令選項,是一個功能強(qiáng)大的分析工具,當(dāng)然還可以做反匯編的工具使用。

說到Otool就不得不提到mach-O ,那什么是mach-O??

Mach-O格式全稱為Mach Object文件格式的縮寫,是mac上可執(zhí)行文件的格式,類似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)。

Mach-o包含三個基本區(qū)域:

1.頭部(header structure)。Mach-o的頭部幫助內(nèi)核迅速確定當(dāng)前文件所支持的CPU架構(gòu)。

2.加載命令(load command)。

3.段(segment)。可以擁有多個段(segment),每個段可以擁有零個或多個區(qū)域(section)。每一個段(segment)都擁有一段虛擬地址映射到進(jìn)程的地址空間。

4.鏈接信息。一個完整的用戶級Mach-o文件的末端是鏈接信息。其中包含了動態(tài)加載器用來鏈接可執(zhí)行文件或者依賴庫所需使用的符號表,字符串表等等。 如下圖左邊就是蘋果給出的mach-O格式的示意圖 ,第二個圖是我們使用machOView來分析某個可執(zhí)行文件中的armv7的格式??梢钥闯鏊麄儍烧叩年P(guān)系是對應(yīng)的。



我們是如何找出工程中所使用的函數(shù)列表的呢,其實就是使用命令字otool -V -s __DATA __objc_selrefs 項目.app/項目 | open -f。這里的項目地址指的是項目.app的路徑地址,在Xcode7中的路徑為

/Users/用戶名/Library/Developer/Xcode/DerivedData/項目名/Build/Products/Debug-iphonesimulator/項目名.app/項目名

另外一個要注意的是-V要大寫,因為大寫和小寫的命令是不一樣的。當(dāng)然大家也可以試試把DATA __objc_selrefs改成TEXT __objc_classname看看有什么不一樣。

下面就聊一聊如何對可執(zhí)行文件進(jìn)行瘦身。

a.查找無用selector

結(jié)合LinkMap文件的__TEXT.__text,通過正則表達(dá)式([+|-][.+\s(.+)]),我們可以提取當(dāng)前可執(zhí)行文件里所有objc類方法和實例方法(SelectorsAll)。再使用otool命令otool -v -s __DATA __objc_selrefs逆向__DATA.__objc_selrefs段,提取可執(zhí)行文件里引用到的方法名(UsedSelectorsAll),我們可以大致分析出SelectorsAll里哪些方法是沒有被引用的(SelectorsAll-UsedSelectorsAll)。注意,系統(tǒng)API的Protocol可能被列入無用方法名單里,如UITableViewDelegate的方法,我們只需要對這些Protocol里的方法加入白名單過濾即可。

另外第三方庫的無用selector也可以這樣掃出來的。

b. 查找無用oc類

查找無用oc類有兩種方式,一種是類似于查找無用資源,通過搜索"[ClassName alloc/new"、"ClassName *"、"[ClassName class]"等關(guān)鍵字在代碼里是否出現(xiàn)。另一種是通過otool命令逆向__DATA.__objc_classlist段和__DATA.__objc_classrefs段來獲取當(dāng)前所有oc類和被引用的oc類,兩個集合相減就是無用oc類。

c.掃描重復(fù)代碼

可以利用第三方工具simian掃描(怎么使用自己去搜)。掃描重復(fù)代碼,但維護(hù)成本過高,因為需要重構(gòu)代碼,沒有刪除代碼來得直接(看自己的夜霧需求)。

(3).編譯選項優(yōu)化

這個最有用的一個選項是Strip Linked Product / Deployment Postprocessing / Symbols Hidden by Default 在release版本應(yīng)該設(shè)為yes

原理是打開這兩個選項后構(gòu)建ipa會去除掉symbol符號,就是那些類名啊函數(shù)名啊啥的。這樣子的影響就是運(yùn)行時你沒法進(jìn)行線程回溯,符號都沒了回溯了也是亂碼。但是不會影響正常的崩潰日志生成和解析。在本機(jī)專門測試過,如果使用符號表來解析崩潰日志,則完全不受影響。

第二個 就是 Build Settings->Optimization Level有幾個編譯優(yōu)化選項,release版應(yīng)該選擇Fastest, Smalllest,這個選項會開啟那些不增加代碼大小的全部優(yōu)化,并讓可執(zhí)行文件盡可能小(不過默認(rèn)就是如此)。


終于你也看完了這么多內(nèi)容,你以為總算看完了,呵呵,你還是太年輕了,同志們注意了,我要開始裝逼了,


接下來我要把更高級點(diǎn)的 iOS瘦身(從方案來自滴滴大神的分享,說實在的這也算是代碼級別的瘦身,這不過這種方法發(fā)揮了極致

眾所周知,代碼之間存在調(diào)用關(guān)系。假設(shè)iOS APP的主入口為-[UIApplication main],則所有開發(fā)者的源代碼(包括第三方庫)可分為兩類:存在一條調(diào)用路徑,使得代碼可以被主入口最終調(diào)用(稱此類代碼為被最終調(diào)用);不存在一條調(diào)用路徑,使得代碼最終不能被主入口調(diào)用(稱此類代碼為未被最終調(diào)用)。

假設(shè)有一個源代碼級別的分析工具(或編譯器),可以輔助分析代碼間的調(diào)用關(guān)系,這樣就使得分析最終被調(diào)用代碼成為可能,剩下的就是未被最終調(diào)用的代碼。

這種工具目前有成熟可用的嗎?答案是肯定的,就是clang插件。除可用于分析未被最終調(diào)用代碼外,clang還可輔助發(fā)現(xiàn)重復(fù)代碼。作為LLVM提供的編譯器前端,clang可將用戶的源代碼(C/C++/Objective-C)編譯成語言/目標(biāo)設(shè)備無關(guān)的IR(Intermediate Representation)實現(xiàn)。其可提供良好的插件支持,容許用戶在編譯時,運(yùn)行額外的自定義動作。(后來想想其實clang插件可以做更多的事情)

我們的目標(biāo)是使用clang插件減少包大小。其原理是,針對目標(biāo)工程,基于clang的插件特性,開發(fā)者可以編寫插件以分析所有源代碼。編譯過程中,將插件作為clang的參數(shù)載入并生成各種中間文件。編譯完成后,還需編寫一個工具去分析所有包含源碼的方法(包括用戶編寫,以及引入的第三方庫源代碼),檢查這些方法中哪些最終可被程序主入口調(diào)用,剩余即是疑似無用代碼。簡單的一個復(fù)查,移除那些確定無用的代碼,重新編譯,便可以有效去除無用的代碼從而減少包大小。

首先“如何編寫一個clang插件并集成到Xcode” (這個要不你們自己搜吧 實在篇幅命令很長 ,但是按照命令一步一步來很簡單的,沒啥技術(shù)含量)

第二“如何實現(xiàn)代碼級別的包瘦身” (代碼指的是OC中的形如-/+[Class method:\*]這種形式的代碼,調(diào)用關(guān)系典型如下:)

@interface ViewController : UIViewController

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

[self.view setBackgroundColor:[UIColor redColor]];

}

@end

則稱:-[ViewController viewDidLoad]調(diào)用了:

-[UIViewController viewDidLoad]

-[ViewController view](語法糖)

+[UIColor redColor]

-[UIView setBackgroundColor:]

我先緩緩啊 等會兒補(bǔ)充

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容