蘋果對編譯器在不斷優化,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中並沒有實際意義。