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

时间:2016-01-12 18:59:20

标签: objective-c memory-management objective-c-blocks grand-central-dispatch weak-references

我见过以下用法:

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 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很新,并尝试找出最正确的用法。非常感谢关于这一点的任何指导。

3 个答案:

答案 0 :(得分:9)

这取决于所需的行为。

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

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

  • 第二种语法(weakSelf模式)不会保持对视图控制器的强引用,因此如果与块视图控制器关联的视图在块运行时被解除,则视图控制器将被释放,nildoSometingWithObject,因此weakSelf将不会被调用。 (显然,如果视图尚未被解除,视图控制器将不会被释放,nil将不会weakSelf并且将调用该方法。)

    如果视图尚未被解除,则只需要调用相关方法即可。例如,如果方法的唯一目的是更新该视图上的某个UI对象,那么如果视图已被解除,您显然不需要调用该方法。在这种情况下,您通常更喜欢使用weakSelf,以便在不再需要时立即释放视图控制器。

  • 为了完整起见,实际上有这种模式的第三种排列,有时(开玩笑地)称为strongSelf / __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

    此模式与第二个示例非常相似,如果取消分配nil,则不会调用方法。当您需要弱引用时使用此模式,但是(a)您需要确保在块运行时不释放它;或(b)当你需要测试是否# Call with year month day # e.g. convert_date_to_long 2015 01 01 function convert_date_to_long() { date="${1}${2}${3}" let long_date=$date if [[ $long_date -gt 0 ]]; then echo "Numeric date: ${long_date}" fi } 时,但是要避免竞争条件。

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:-2)

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

__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/