天天看點

[iOS]dispatch_after()中self和weakself的使用

蘋果對編譯器在不斷優化,GCD方法中的block基本都不需要使用weakself,并不會造成循環引用。

dispatch_after官方文檔中對block部分的說明:

[iOS]dispatch_after()中self和weakself的使用

一:使用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");
}      

輸出結果

[iOS]dispatch_after()中self和weakself的使用

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];
}      
[iOS]dispatch_after()中self和weakself的使用

在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中并沒有實際意義。