很多剛入門的寶寶面對block是心虛的,因為一提到block就會聯想到:如果用的不好會出現循環引用引起內存泄漏問題,有時候想用但是自己又沒有能發現循環引用的洞察力,所以在遇到block存在的地方,就使用__weak type(self) weakSelf = self;(被視為解決循環引用的必備良藥) 這句話加上確實能保證不會出現循環引用的情況,但是并不是所有使用block的地方都會出現循環引用的,所以這個要具體問題具體對待,該用時那必須得用,沒必要的時候,也就沒有必要畫蛇添足了。
下面列舉一處常見使用Block的例子,但是一般不會輕易出現循環引用,只要把關鍵點處理好就不會出現循環引用的問題。
例子一:UIAlertController(彈出框視圖控制器)想必大家再也熟悉不過了
//點擊按鈕彈出提示框
-(void)btnAction:(id)sender{
NSLog(@"彈出框");
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"彈出框" message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Class****%@",[self class]);
//明目張膽在block中引用self,很多懼怕block中引用self會出現循環引用的寶寶會來這么一句:__weak type(self) weakSelf = self;
//接著NSLog(@"Class****%@",[weakSelf class]);然后心里才放心!其實這些都是畫蛇添足,完全沒有必要的!
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[alert addAction: ok];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
這里把引用關系列一下就明白為什么安全無事了:
引用關系圖.png
這里根本都沒有造成閉環構成循環引用,前提是:你沒有把UIAlertController對象或者UIAlertAction對象作為當前類的成員屬性,一但self強引用了UIAlertController對象或者強引用了UIAlertAction對象,那么就構成閉環了,循環引用就會出現。一般編程中,沒有必要把UIAlertController對象或者UIAlertAction對象作為當前視圖控制器類的成員屬性,去讓self去持有它們的引用,一般都是像在本例中:在方法體中作為局部臨時對象使用(self不會持有臨時對象的引用),局部臨時對象作用域只限制在方法體內部,也就是說這些臨時對象的生命周期只限制在方法內部,一但方法執行完畢,這些臨時創建的指針變量就會被置為
nil
,如果指針被置為nil
,那么它原來所指臨時對象就會被銷毀。記住:局部指針變量,出了作用域就會被置為
nil
,所指向的對象也會立即被系統釋放。
想測試到底會不會出現循環引用的有一個很簡單的方法:就是在self.navigationController中pop掉當前控制器對象的時候(前提使用UINavigationController作為根視圖控制器),看看當前視圖控制器類中dealloc方法是否被執行,如果成功執行說明沒有其他對象引用當前即將要pop掉的視圖控制器,如果不執行,那么基本可以斷定是由于代碼中出現了循環引用,導致內存泄漏,無法得到釋放的緣故。