春節前抽空花了一天的時間將手頭的工程從MRC轉成了ARC,而後陸陸續續地修復一部分由於轉ARC引發的內存泄漏和崩潰,到目前爲止工程也算是比較穩定了,抽空記上一筆。(雖然說這種事情這輩子估計都只會作這麼一次了,可是能夠留點經驗給後來的童鞋)性能
這個工程啓動於12年末13年初,一開始人手少工期短,須要儘快地出demo,同時抱着對面世才一年多的ARC不太信任的態度沿用了最熟悉的MRC。可是隨着工程投入的人手增多,使用MRC的各類缺點也暴露無遺:ui
1.零星的內存泄漏增多,致使每次發版本以前都要捋一遍:費時費力不討好。雖然我一直以爲iOS下這種零星的內存泄漏並非多大的事,真正壓死一個App的泄漏永遠是某些Bitmap的泄漏。可是這種零星泄漏仍舊會帶來不少麻煩,因此仍是須要解決一下。spa
2.沒法享受到ARC下weak關鍵字帶來的好處:總有童鞋忘記在對象析構時去置空delegate。一個比較典型的例子是帶Scrollview(尤爲是MKMapView)的VC。若是VC析構時不置空Scrollview的delegate,那麼若此時Scrollview還正處於滑動狀態,就很容易出現崩潰。緣由是:Scrollview在滑動時有一個Timer retain自身,此時退出VC並不會使得Scrollview同步析構。而當Timer fire時,Scrollview調用其delegate方法就訪問了野指針。指針
3.ARC下編譯器對於retain cycle的檢測更爲嚴格。(我的使用後的感受)對象
4.愈來愈多的第三方庫只提供ARC版本,雖然打標記能夠解決問題,但增長了無謂的工做。內存
基於以上4點理由,因而選了春節前一個月高風黑夜悄悄地完成工程的ARC轉換。23333333333333333編譯器
準備工做同步
1.一個MRC模式的工程。(嗯!)it
2.一個合適版本的XCode。(你是雞丁?不,我是喜兒肉絲)雖然XCode4以後就支持了ARC的自動轉換,可是對ObjC++的支持卻仍是在XCode5以後。編譯
3.一臺性能彪悍的機器。我的悲慘經歷:某天下午用本身那臺老爺機作了一次轉換,結果在最後一步機器直接卡死,重啓後XCode也沒法使用,最後只得重裝XCode了事。
使用XCode作最基本的轉換
1.開啓即便出錯也繼續編譯的選項:"Preferences" -> "General" -> "continue building after error" 。當轉換開始後工程將出現大量的錯誤,與其每次fix一個錯誤再來一遍,還不如一口氣讓編譯器把全部的錯誤都先彙報出來,再一一解決。(咱們的工程大約20來萬代碼,檢查出了近200個錯誤)
2.檢查第三方庫和本身的代碼。對於第三方庫,有ARC版本就進行替換,沒有則打上-fno-objc-arc的標記(固然若是第三方庫比較簡單,也能夠直接作轉換)。而本身的代碼則推薦所有作ARC的轉換。
3.使用XCode提供的Convert to Objective-C ARC功能,選擇當前須要轉換的工程並執行。
4.正常狀況會出現比較多的錯誤和retain-cycle的warning,推薦優先解決掉全部error,而warning暫時不處理,等轉換完畢編譯經過後再進行處理。而error和warning通常也就是下面幾種狀況:
a.對於NSObject和CF對象沒有使用bridge cast,大多數狀況下直接按照XCode的推薦方式進行fix便可。
b.原來MRC下使用了ARC下不容許使用的方法,如NSMakeCollectable。
c.原先使用__block關鍵字避免循環引用的地方在ARC每每會引發循環引用,緣由是__block在MRC和ARC下的語意不一樣,MRC下生成的__block結構體內只是簡單地指向原值地址,而ARC下則是由__block結構體持有了原值,使用__weak進行修改便可。
處理完畢後重復第三步直到順利編譯經過。
後續處理
完成前面的步驟整個轉換就算完成了百分之九十,可是正所謂行百里者半九十,接下去的任務更加艱鉅,更須要認真對待。
1.檢查工程內的全部文件,包括是否設置了合理的編譯選項和被包含在工程內:XCode彷佛有個bug,在轉換完成後部分文件會被移出工程,部分文件原先打好的-fno-objc-arc標記也會被重置。
2.運行Instrument,檢查內存泄漏:此時存在的內存泄漏大可能是一些對ARC不適用的MRC寫法。典型的狀況即是將delegate做爲類內部成員變量,在轉換爲ARC後系XCode並不會在這些變量前面打上weak的標記,致使了循環引用,須要本身手動添加。
3.對你的程序進行冒煙,儘可能走完主流程,檢查是否有必現崩潰。通常都是由錯誤的bridge cast和使用MRC時的不規範寫法引發:如萬惡的[self retain],在ARC轉換時XCode直接去掉這句話,這樣就致使原先依賴於此的類每每在初始化後就直接被釋放,形成野指針訪問。(吐槽下,不管是MRC仍是ARC下,本身去擁有本身這種作法都是不太好的作法)