在SDWebImage代码中解释__weak和__strong使用原因

时间:2013-02-16 07:28:49

标签: iphone ios automatic-ref-counting objective-c-blocks sdwebimage

我认为我很了解强弱关键词,但我不明白它是如何在下面的代码中使用的。此代码来自github上的Olivier Poitrey的SDWebImage。我理解强关键字和弱关键字,如下所述:Explanation of strong and weak storage in iOS5

以下代码以对我好奇的方式使用__weak和__strong关键字。这不是一个孩子 - 父母的关系或委托模式,因为我习惯看到弱的使用。但是,我确信这是一个经常使用的模式,正如我之前在其他代码中看到的那样。它在另一个线程上运行的块之前设置__weak引用。然后,在块内,它将弱引用设置为强引用。

我确信这个优雅而优雅的代码,所以我试图理解它。如果在块运行之前“self”不再存在,则弱自引用将为零。块运行时,强引用也将设置为零。因此,它将知道杀死剩下的操作,因为自我不再存在。我做对了吗?

现在,如果我们不使用__weak和__strong关键字会发生什么?如果我们只是在块内检查self == nil会怎么样?由于块复制整棵树,“自我”永远不会是零吗?

有人可以帮助揭开这段令人敬畏的代码的神秘面纱吗?有人可以验证或否定我的假设吗?

- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock;
{
    [self cancelCurrentImageLoad];

    self.image = placeholder;

    if (url)
    {
        __weak UIImageView *wself = self;
        id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
        {
            __strong UIImageView *sself = wself;
            if (!sself) return;
            if (image)
            {
                sself.image = image;
                [sself setNeedsLayout];
            }
            if (completedBlock && finished)
            {
                completedBlock(image, error, cacheType);
            }
        }];
        objc_setAssociatedObject(self, &operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
}

2 个答案:

答案 0 :(得分:7)

downloadWithUrl:方法可能需要很长时间。在那段时间内,用户可能决定离开,从而消除了对SDWebImage对象的需求。为了便于早期清理对象,外部self引用很弱。这样, downloadWithUrl不会阻止SDWebImage被解除分配

当然,如果您真的想使用self,则需要强大的参考。因此,downloadWithUrl的完成时块会强制引用self。如果该对象在此时间消失,sself将为nil。否则,它将是一个有效的强引用,表示SDWebImage对象仍在,并且该对象将在此时完成其工作。

答案 1 :(得分:3)

  

我确信这个优雅而优雅的代码,所以我试图理解它。如果在块运行之前“self”不再存在,则弱自引用将为零。块运行时,强引用也将设置为零。因此,它将知道杀死剩下的操作,因为自我不再存在。我做对了吗?

不,你在考虑这个问题。 __weak存储限定符就是:限定符。 __weak的对象是显式取消的,但如果从强变量分配,它们不仅会自动设置为nil。事实上,那会破坏弱变量的目的!

  

现在,如果我们不使用__weak和__strong关键字会发生什么?如果我们只是在块内检查self == nil会怎么样? “自我”永远不会是零,因为该块会复制整个树吗?

检查实际上是不必要的,因为运行时将消息解析为nil为nil(然而,对于以后的实现,它可能很重要,谁知道)。你很喜欢这个:在那里没有那么“弱到强”的舞蹈,然后自我将被阻挡,有可能创造一个非常令人讨厌的保留周期。这是我可以开始将这一切联系在一起的地方:

因为我们不希望块保留我们的变量,但我们也希望它在块的范围内变强,所以没有任何奇怪的事情发生,self被分配给弱指针。当块发生在我们的弱指针上时,它不允许保留它,所以self的引用计数保持不变,然后一旦在块内,我们回到强自变量,因此弱的指针被释放,我们不必再担心了。实际上,这意味着我们有一个可靠的保证,即在块的整个执行过程中self都是值或nil。很整洁,呵呵?