蘋果對編譯器在不斷優化,GCD方法中的block基本都不需要使用weakself,并不會造成循環引用。
dispatch_after官方文檔中對block部分的說明:
一:使用self
從ViewControllerA push 到 ViewControllerB。ViewControllerB中代碼:
#import "ViewControllerB.h"
@interface ViewControllerB ()
@end
@implementation ViewControllerB
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor blueColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self log];
});
[self.navigationController popViewControllerAnimated:YES];
}
- (void)log
{
NSLog(@"Finish");
}
- (void)dealloc
{
NSLog(@"dealloc");
}
輸出結果
pop事件後,ViewControllerB關閉,但并沒有立刻調用dealloc方法。而是等待倒計時結束後,log方法執行完成,然後再調用dealloc方法。
整個過程不會發生循環引用,在dispatch_after時間結束之前,block強持有self,時間結束後,block被釋放,随後ViewControllerB被釋放。
二:使用weakself
将代碼修改為
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"pop action");
__weak ViewControllerB *weakself = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakself log];
});
[self.navigationController popViewControllerAnimated:YES];
}
在pop之後,立即調用了dealloc方法,ViewControllerB被釋放。不會調用log方法。
三:使用weak-strong dance
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"pop action");
__weak ViewControllerB *weakself = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong ViewControllerB *strongself = weakself;
[strongself log];
});
[self.navigationController popViewControllerAnimated:YES];
}
結果與使用weakself相同。
四:結論
1:上述代碼中,如果去除[self.navigationController popViewControllerAnimated:YES]操作,三種方法都能夠正常完成任務。
2:當block時間内,如果傳回上一頁面或其他類似操作,導緻目前ViewController消失時。
使用self,ViewController會被block強引用,block時間截止完成回調後,釋放block,進而釋放ViewController。
使用weakself時,不存在強引用,ViewController會被直接銷毀。
3:weak-strong dance,在dispatch_after中并沒有實際意義。