iOS中Block的循環引用問題
每週總結,第一週開始啦,最近在看AFNetworking源碼時,看到了__strong的使用,很慚愧的說在平時開發中從來沒有使用過__strong self ,除此之外,發現自己對Block的循環引用理解的也不深刻,今天就總結下block的循環引用問題
AFNetworking中__strongSelf應用如下
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
本文將從以下幾個方面介紹ARC下block的循環引用問題:
1. 什麼是循環引用
2. 循環引用的結果
3. ARC下Block怎樣產生的循環引用
4. 怎麼樣解決循環引用
1、什麼是循環引用?
兩個對象相互持有,導致兩個對象都不能釋放,造成內存泄漏。
2、如何產生了循環引用
觀察以下代碼存在些什麼問題
@interface ViewController ()
@property (nonatomic, copy) void(^ testBlock)();
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.testBlock = ^(void){
[self doSomeThing];
};
}
-(void)doSomeThing{
NSLog(@"you are doing something");
}
@end
在上述代碼中,XCode編譯後提示[self doSomeThing],這一行可能會導致循環引用。
因爲無論testBlock是copy還是strong屬性,self都強引用了testBlock,在testBlock內部又調用了self,此時,testBlock強引用self(self的引用計數+1),導致ViewController實例無法被釋放,因爲自身的變量的引用計數永遠大於1,循環引用。
爲了解決這種問題,可以聲明一個__weak變量指向self,在blcok中使用這個__weak變量,就不會導致self的引用計數+1,不會出現循環引用的問題了。
@interface ViewController ()
@property (nonatomic, copy) void(^ testBlock)();
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak __typeof(self)weakSelf = self;
self.testBlock = ^(void){
[weakSelf doSomeThing];
};
}
-(void)doSomeThing{
NSLog(@"you are doing something");
}
@end
循環引用問題解決了,但是這時還有其他的問題,當你加了weakSelf後,Block中的self隨時都會有被釋放的可能,所以會出現一種情況,在異步調用的時候,執行到Block代碼塊時,self可能已經釋放爲nil了,所以爲了避免這種情況發生,我們會重新strong self。一般情況下,我們都應該這麼做,畢竟這麼做是沒什麼風險,除非你不關心self在執行過程中變成nil,或者你確定它不會變成nil。
__weak __typeof(self)weakSelf = self;
self.testBlock = ^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doSomeThing];
}];
weakSelf是爲了block弱引用self,避免循環引用,而再聲明一個strongSelf是因爲一旦進入block執行,就不允許self在這個執行過程中釋放。block執行完後這個strongSelf會自動釋放,沒有循環引用問題。
到此,有關本人對weakSelf的使用歷程就介紹完畢啦,後續學習到新的知識,再更新,收車。