今天不寫教程,和大伙分享一下IOS在記憶體泄漏方面的文章..... ...
前言:
好久沒寫文章了,最近先是重構IT戀、又重寫IT戀中。
Sagit框架也不斷的更新,調整,現在感覺已完美了了相當的多。
今天不寫教程,先簡單分享一下技術內容。
1:見Block必有:#define WeakSelf __weak typeof(self) this = self;
故事要從這這裡說起:
當初番完這代碼後,發現到處都有這個鬼東西,然後就去百度了一下,然後大意是為了:
解決雙向引用導致的記憶體無法釋放問題
簡單的表述如下:
self 強引用指向=》block;
block 也強引用批向=>self;
這時候就出事了,解決的方法是,把其中一個改成弱指向。
而WeakSelf的定義,就是讓block改成弱引用,這樣無論self是不是強引用的指向block都無關緊要了。
當然,更精緻的做法是:先預判self有沒有強引用指向block,沒有,就不用WeakSelf定義了。
不過,一般新手搞不明白內涵,無法做出有效的預判,所以見block就有WeakSelf也就相隨相生了。
2:其它場景的雙向引用:UIViewController與UIView的糾纏
首先,預設UIViewController有一個強引用指向了UIView,這是系統定義的,我們改不了:
所以,如果UIView里再出現strong或retain指回UIController,就會導致UIViewController和UIView雙雙無法釋放問題。
這個問題,在我剛寫Sagit框架時,只在意功能,沒在意這些,就犯了這個錯誤:
錯誤的寫法是這樣的:
現在改正後的寫法是這樣的:
3:事情沒有這麼簡單:UIView子控制項綁定事件指向Controller
看一行Sagit的代碼,關註後面的addClick:
[[[[sagit addButton:@"Login" title:@"登錄" font:40] width:450 height:80] onBottom:@"pwdLine" y:149] addClick:@"loginClick"];
對於事件流程關於Sagit的前面幾篇有說了,這裡說一下框架的流程代碼:
1:系統自動添加了一個UITapGestureRecognizer,並指定到一個固定的click方法; 2:將方法名稱和target存到自身的NSDictionary的字典中(框架為每個UIView都擴展了一個Dictionary)(就是這裡造成強引用了Controller). 3:事件點擊時:先觸發系統預設的click,然後click事件:從字典里取出方法名和target,找到SEL並動態執行。 PS:設計成動態執行的好處:可以在執行前處理一些其它事情:比如將addClick參數:loginClick改成AgeButton.click,這樣可以分解參數後,去執行AgeButton上的事件
執行的代碼是這樣的,由於是動態執行,少不了還有一個警告:
接下來,就是怎麼消滅事件里對Controller的強引用:
1:找了資料,發現有個NSMapTable,是弱引用的字典,於是把NSDictionary換成它,結果:參不忍睹,界面錯亂。【大概是弱引用特別容易丟失數據】
2:嘗試用一個全局的第三方的字典來存,結果也悲哀了! 3:最後想到了一個方法,不直接存Controller,只存字元串:1和0 ,在最終執行的時候,再去找。
代碼是這樣的:
真難為我這麼聰明,想著大功告成,運行,釋放了,成功了!!!
然後又悲哀了:
然後就動不動就到main含數了,讓我怎麼猜?說好的全局斷點呢?你咋不斷呢?
搜了搜百度,想想要調度記憶體,那就一個蛋騰,還是靠猜吧。
後來,根據釋放的順序,和最後的關鍵字,大概是這樣猜的:
控制器被釋放了,這時候UIView還沒釋放,然後系統又給UIView綁字的事件發消息,結果遇到野指針,悲傷的故事發生了。
於是,我做了一個艱難的決定,在UIController的deallow中寫了這樣的代碼:
-(void)dealloc { [self.view removeAllsubViews];//處理記憶體釋放後的異常。 NSLog(@"%@ ->UIViewControlelr relase", [self class]); }
這執行dealloc前,畢竟Controller還是活著的,這時候趕緊把UIView的東西給清了,然後,發現完美,運行起來很6!
總結:
當我很6的解決完上述問題後,就開始寫文章了想分享一下了,然後寫了開頭,發現:
咦,好像UITableView和UITableViewCell,好像也有雙向引用問題。
因為我給Cell加了個屬性,指向Table,運行,果然,Shit,連Controller和父的UIView都釋放了,你UITableView做為子UI居然不釋放!!!!
沒天理,繼續折騰,然後UITableView搞釋放了,又發現UITableViewCell不釋放了(這個Cell通常又會是一大堆UI)。
再然後,發現Push兩層回來,又掛Crash了。
現在正在全力搶救!!!解決完再來寫下篇!!!
操,發現為了釋放那點記憶體的代價,折騰起來真慘過不釋放算了〜〜〜〜