春節(jié)前抽空花了一天的時(shí)間將手頭的工程從MRC轉(zhuǎn)成了ARC,然后陸陸續(xù)續(xù)地修復(fù)一部分因?yàn)檗D(zhuǎn)ARC引起的內(nèi)存泄漏和崩潰,到目前為止工程也算是比較穩(wěn)定了,抽空記上一筆。(雖說這種事情這輩子估計(jì)都只會(huì)做這么一次了,但是可以留點(diǎn)經(jīng)驗(yàn)給后來的童鞋)
這個(gè)工程啟動(dòng)于12年底13年初,一開始人手少工期短,需要盡快地出demo,同時(shí)抱著對(duì)面世才一年多的ARC不太信任的態(tài)度沿用了最熟悉的MRC。但是隨著工程投入的人手增多,使用MRC的各種缺點(diǎn)也暴露無遺:
零星的內(nèi)存泄漏增多,導(dǎo)致每次發(fā)版本之前都要捋一遍:費(fèi)時(shí)費(fèi)力不討好。雖然我一直覺得iOS下這種零星的內(nèi)存泄漏并不是多大的事,真正壓死一個(gè)App的泄漏永遠(yuǎn)是某些Bitmap的泄漏。但是這種零星泄漏仍舊會(huì)帶來很多麻煩,所以還是需要解決一下。
無法享受到ARC下weak關(guān)鍵字帶來的好處:總有童鞋忘記在對(duì)象析構(gòu)時(shí)去置空delegate。系統(tǒng)控件如UIScrollView,MKMapView的delegate仍舊需要自己釋放,但是自定義procotol并將屬性設(shè)為weak的delegate就可以獲得weak屬性帶來的好處。
ARC下編譯器對(duì)于retain cycle的檢測(cè)更為嚴(yán)格。(個(gè)人使用后的感覺)
越來越多的第三方庫只提供ARC版本,雖然打標(biāo)記可以解決問題,但增加了無謂的工作。
基于以上4點(diǎn)理由,于是選了春節(jié)前一個(gè)月高風(fēng)黑夜悄悄地完成工程的ARC轉(zhuǎn)換。23333333333333333
準(zhǔn)備工作
1.一個(gè)MRC模式的工程。(嗯!)
2.一個(gè)合適版本的XCode。(你是雞???不,我是喜兒肉絲)雖然XCode4之后就支持了ARC的自動(dòng)轉(zhuǎn)換,但是對(duì)ObjC++的支持卻還是在XCode5之后。
3.一臺(tái)性能彪悍的機(jī)器。個(gè)人悲慘經(jīng)歷:某天下午用自己那臺(tái)老爺機(jī)做了一次轉(zhuǎn)換,結(jié)果在最后一步機(jī)器直接卡死,重啟后XCode也無法使用,最后只得重裝XCode了事。
使用XCode做最基本的轉(zhuǎn)換
1.開啟即使出錯(cuò)也繼續(xù)編譯的選項(xiàng):”Preferences” -> “General” -> “continue building after error” 。當(dāng)轉(zhuǎn)換開始后工程將出現(xiàn)大量的錯(cuò)誤,與其每次fix一個(gè)錯(cuò)誤再來一遍,還不如一口氣讓編譯器把所有的錯(cuò)誤都先匯報(bào)出來,再一一解決。(我們的工程大約20來萬代碼,檢查出了近200個(gè)錯(cuò)誤)
2.檢查第三方庫和自己的代碼。對(duì)于第三方庫,有ARC版本就進(jìn)行替換,沒有則打上-fno-objc-arc的標(biāo)記(當(dāng)然如果第三方庫比較簡(jiǎn)單,也可以直接做轉(zhuǎn)換)。而自己的代碼則推薦全部做ARC的轉(zhuǎn)換。
3.使用XCode提供的Convert to Objective-C ARC功能,選擇當(dāng)前需要轉(zhuǎn)換的工程并執(zhí)行。
4.正常情況會(huì)出現(xiàn)比較多的錯(cuò)誤和retain-cycle的warning,推薦優(yōu)先解決掉所有error,而warning暫時(shí)不處理,等轉(zhuǎn)換完畢編譯通過后再進(jìn)行處理。而error和warning一般也就是下面幾種情況:
對(duì)于NSObject和CF對(duì)象沒有使用bridge cast,大多數(shù)情況下直接按照XCode的推薦方式進(jìn)行fix即可。
原來MRC下使用了ARC下不允許使用的方法,如NSMakeCollectable。
原先使用__block關(guān)鍵字避免循環(huán)引用的地方在ARC往往會(huì)引起循環(huán)引用,原因是__block在MRC和ARC下的語意不同,MRC下生成的__block結(jié)構(gòu)體內(nèi)只是簡(jiǎn)單地指向原值地址,而ARC下則是由__block結(jié)構(gòu)體持有了原值,使用__weak進(jìn)行修改即可。
處理完畢后重復(fù)第三步直到順利編譯通過。
后續(xù)處理
完成前面的步驟整個(gè)轉(zhuǎn)換就算完成了百分之九十,但是正所謂行百里者半九十,接下去的任務(wù)更加艱巨,更需要認(rèn)真對(duì)待。
1.檢查工程內(nèi)的所有文件,包括是否設(shè)置了合理的編譯選項(xiàng)和被包含在工程內(nèi):XCode似乎有個(gè)bug,在轉(zhuǎn)換完成后部分文件會(huì)被移出工程,部分文件原先打好的-fno-objc-arc標(biāo)記也會(huì)被重置。
2.運(yùn)行Instrument,檢查內(nèi)存泄漏:此時(shí)存在的內(nèi)存泄漏大多是一些對(duì)ARC不適用的MRC寫法。典型的情況便是將delegate作為類內(nèi)部成員變量,在轉(zhuǎn)換為ARC后系XCode并不會(huì)在這些變量前面打上weak的標(biāo)記,導(dǎo)致了循環(huán)引用,需要自己手動(dòng)添加。
3.對(duì)你的程序進(jìn)行冒煙,盡量走完主流程,檢查是否有必現(xiàn)崩潰。一般都是由錯(cuò)誤的bridge cast和使用MRC時(shí)的不規(guī)范寫法引起:如萬惡的[self retain],在ARC轉(zhuǎn)換時(shí)XCode直接去掉這句話,這樣就導(dǎo)致原先依賴于此的類往往在初始化后就直接被釋放,造成野指針訪問。(吐槽下,無論是MRC還是ARC下,自己去擁有自己這種做法都是不太好的做法)
4.扔給QA繼續(xù)測(cè)試……23333333333333333333333
原文鏈接?MRC工程轉(zhuǎn)ARC工程小記