1. 程式人生 > >解決iOS開發中涉及到的retain cycle導致控制器無法釋放的問題

解決iOS開發中涉及到的retain cycle導致控制器無法釋放的問題

這幾天碰到專案中一個bug,從一個列表進入任務詳情頁面,回覆一條資訊後,會導致列表中所有的cell點選進去全都是剛剛回復的那條任務詳情。bug不細說,因為同事之前改過一個問題,有一個對列表資料賦值的操作,但是這個操作只會在介面呼叫完成後在詳情控制器裡進行,如果退出了,那麼控制器銷燬後就不會賦值,也就沒有後來的bug。因此我檢測了記憶體,除錯了控制器的dealloc方法,果然,控制器沒有被釋放,應該是存在一些retaincycle導致的。

這個問題困擾了我三天,因為這個控制器有4個內嵌控制器,主控制器不能釋放,4個內嵌控制器也不能釋放,如果有幾個retain環的話,那我碰巧改過一個之後,也解決不了問題,為了不引入新bug,只能改回去,這樣就無解了。所以解決了一個之後必須記錄下來,有思路。

這裡比較重要的是,在arc下要打印出關注的控制器的retaincount。這裡用到一個方法-

NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)theVC));

在跳轉過來的控制器中,用weak方式持有一個關注的控制器,就可以在這個關注的控制器被pop的時候列印他的值了。

這樣,每次解決一個潛在問題之後,就可以看到retaincount減少了。我首先把控制器中所有可能有問題的程式碼全部註釋掉,然後看retaincount。看一下當dealloc可以執行時,這個retaincount的值是多少。然後,再去關注的控制器裡面,分部分的註釋程式碼,直到註釋了一小部分程式碼之後,這個控制器的dealloc就可以被執行了,然後逐步縮小範圍。縮小到最後,差不多都是strong代理,block迴圈引用(self.request標記了介面呼叫),以及一些cell用strong引用所在控制器的問題。還有一個是關聯物件問題,在封裝sdwebimage的時候,關聯物件強引用了所在控制器。這樣,分別除錯了五個控制器,最終解決了retaincycle引起的記憶體洩露問題。

因為retain cycle引起的記憶體洩露現象不明顯,只有在引起bug的時候可能才引起重視。所以,最終積累多了,很難除錯。我前兩天的工作進度很慢,因為沒有除錯思路。今天確定這個思路之後,用控制變數法迅速找到了這幾處問題並解決。因為這個比較底層,順帶解決了幾個其他位置的bug,也增加了穩定性,降低了因記憶體問題崩潰的機率。其實在開發的時候,每個控制器下面都加上dealloc方法並打上斷點,可以預防這種問題。