前段時間寫項目的時候我在每個block使用前我都加了一個__weak來修飾用@property描述的屬性,項目寫的差不多了回頭來反思,總覺得這種寫太麻煩了,回想起來,還是由於自己對於循環引用造成的原因理解不夠透徹,才導致做了很多的無用功。
廢話不多說,上代碼了 :
/*
// way 1 獲取數據
model = [[MoveModel alloc] init];
model.successBlock = ^(id returnBlock) {
NSArray *array = (NSArray *)returnBlock;
_dataArray = array;
[mainTableview reloadData];
};
[model getMoveData];
*/
/*
// way 2 獲取數據
[MoveModel GetDataSuccessBlock:^(id returnValues) {
NSArray *array = (NSArray *)returnValues;
_dataArray = array;
[mainTableview reloadData];
}];
*/
這兩種方式都是從別的類中獲取數據的方法,way1采用的是屬性block,way2采用的是參數block,而block內部的數據處理方式是一樣的,但事實是way1造成了循環引用,而way2卻沒有。---不要問我怎么知道的,我就是知道~~
block在iOS開發中視為對象因此生命周期會一直等到持有者的生命周期結束了才會結束另外一方面
由於block的捕獲變量的機制使得block的對象也可能被block持有從而造成循環引用造成內存泄露
第一種情況就是這樣的,block在控制器內部實現的,它的持有者是控制器本身,而在block內部又調用了_dataArray,它又持有了控制器。最終內存泄露了。
解決辦法: 1:聲明 weakSelf
typeof(self) __weak weakSelf = self
block內部的_dataArray 換成weakSelf.dataArray
但是這樣又會產生另外一種特殊情況,就是在回調block的時候,block中的對象很有可能已經釋放了,找不到對象會導致crash。這種情況比較少見,但是需要防范。
2 在block內部在聲明一個_strong 來修飾weakSelf 就行了。
下面是afnetworking中的源碼,既處理了循環引用的問題,又防范了突發情況的產生,處理方式值得借鑒:
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
