为什么我不在传递给 dispatch_after() 的块中使用指向自身的弱指针?

Why would I not use a weak pointer to self in a Block passed to dispatch_after()?

我看到了以下使用:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [self doSometingWithObject:obj1 andAnotherObject:obj2];
});

但是它不应该在块中使用 weak self 吗?

__weak typeof(self) weakSelf = self;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [weakSelf doSometingWithObject:obj1 andAnotherObject:obj2];
});

我是 GCD 和 Blocks 的新手,正在尝试找出最正确的用法。非常感谢您对此的任何指导。

使用块的更好的部分是这样的:

__weak typeof(self) weakSelf = self;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    __strong __typeof(weakSelf)strongSelf = weakSelf; 
    [strongSelf doSometingWithObject:obj1 andAnotherObject:obj2];
});

在块内创建__strong 引用不会增加内存引用计数。一旦区块完成,它就会被释放。

https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/

指向自身的弱指针用于防止循环保留。第一个代码片段中没有保留周期的风险。

如果您的对象要保留保留您的对象的块,则保留周期将是一个问题,并且如果您的对象仅在它本身被释放时才释放该块释放。在这种情况下,这些条件都不成立。

dispatch_after()会在指定时间后运行提供的区块,然后释放区块。块的释放不依赖于你的对象被释放。没有保留周期。

这取决于所需的行为。

  • 第一个语法(参考块中的self)将保持对视图控制器的强引用,直到dispatch_after触发并且doSometingWithObject成功运行。即使与该视图控制器关联的视图在此期间被取消,也会发生这种情况。

    因此,只有在您绝对需要该方法 运行 的情况下,您才会使用此模式,即使在与该视图控制器关联的视图被关闭之后也是如此。例如,如果该方法正在更新一些模型对象、将某些内容保存到持久存储、发布一些网络请求等。

  • 第二种语法(weakSelf 模式)不会保持对视图控制器的强引用,因此如果与视图控制器关联的视图在块 运行s,视图控制器将被释放并且 weakSelf 将是 nil,因此 doSometingWithObject 将不会被调用。 (显然,如果视图还没有被关闭,视图控制器就不会被释放,weakSelf 不会是 nil 并且那个方法会被调用。)

    如果所讨论的方法只需要在视图尚未关闭时调用,则您将执行此操作。例如,如果该方法的唯一目的是更新该视图上的某些 UI 对象,那么如果视图已经被关闭,您显然不需要调用该方法。在这种情况下,您通常更喜欢使用 weakSelf,以便在不再需要时立即释放视图控制器。

  • 为了完整起见,这个模式实际上还有第三种排列,有时(开玩笑地)称为 weakSelf/strongSelf "dance":

    __weak typeof(self) weakSelf = self;
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        //code to be executed on the main queue after delay
        typeof(self) strongSelf = weakSelf; 
        if (strongSelf) {
            [strongSelf doSomethingWithObject:obj1 andAnotherObject:obj2];
            [strongSelf doSomethingElseWithObject:obj1];
        }
    });
    

    此模式与第二个示例非常相似,如果 self 被释放,则不会调用方法。当您需要弱引用时可以使用此模式,但是 (a) 您需要确保在块 运行ning 时它不会被释放;或 (b) 当您需要测试它是否为 nil 时,但又想避免竞争条件。