解释SDWebImage代码__weak和__strong使用的原因(Explain __weak

2019-07-20 00:17发布

I think I understand strong and weak keywords well, but I don't understand how it's used in the code below. This code is from SDWebImage by Olivier Poitrey available on github. I understand strong and weak keywords as is described here: Explanation of strong and weak storage in iOS5

The code below uses __weak and __strong keywords in a way that is curious to me. It is not a child-parent relationship or delegate pattern as I am used to seeing weak used. However, I'm sure that this is a pattern that is used often, as I've seen it before in other code. It sets a __weak reference before a block that runs on another thread. Then, within the block, it sets the weak reference to a strong reference.

I am certain that this good and elegant code, so I'm trying to understand it. If "self" ceases to exist before the block runs, the weak self reference will zero out. When the block runs, the strong reference will be set to zero as well. Therefore, it will know to kill the rest of the operation since self doesn't exist anymore. Did I get this right?

Now, what would happen if we didn't use __weak and __strong keywords? What if we just checked inside the block whether self == nil. Would "self" never be nil since the block copies the entire tree?

Can someone help demystify this awesome piece of code? Can someone verify or repudiate my hypotheses?

- (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);
    }
}

Answer 1:

downloadWithUrl:方法可能需要很长的时间。 在此期间,用户可以决定导航离开,省去了需要SDWebImage对象。 为了便于对象的早期清理,外self参考较弱。 这样一来, downloadWithUrl不会阻止SDWebImage被释放

当然,如果你真的要使用self ,你需要一个有力的参考。 所以,上完成块downloadWithUrl抓住的强引用self 。 如果物体消失在这个时候, sself将是nil 。 否则,这将是一个有效的强引用,表明SDWebImage对象仍然存在,并且对象将在这个时候完成其工作。



Answer 2:

我相信,这个好和优雅的代码,所以我试图去了解它。 如果“自我”不再块运行之前存在,弱自我引用将归零。 当块运行时,强引用将被设置为零。 因此,它会知道杀操作的其余部分,因为自身不存在了。 难道我得到这个权利?

不,你是在想这颇有几分。 该__weak存储预选赛就是:一个限定。 这是对象__weak明确无保留的,但如果从一个强大的可变分配,他们不只是自动设置为零。 事实上,这会破坏弱变量的宗旨!

现在,如果我们没有使用__weak和__strong关键字,会发生什么? 如果我们只是检查了块内是否自我==为零。 将“自我”绝不可能,因为该块拷贝整个树零?

该检查实际上是不必要的,因为运行时解析消息,零到零(不过,它可能是执行重要后来,谁知道)。 你是当场就与这一个:没有这种有点“弱到强”的舞蹈在那里,然后自我将由块保留,以后有可能创建一个非常讨厌的保留周期。 这是我可以搭售这个开始一起:

因为我们不希望块保留我们的变量,但我们也希望它是块的范围内强所以没有什么奇怪的情况发生,自被分配到一个弱指针。 当块发生在我们弱指针,不允许把它保留下来,所以自我的引用计数保持不变,那么一旦块里面,我们直接回到很强的自变量,以弱者被释放,我们不必担心了。 实际上,这意味着我们有一个坚实的保障,自我是整个区块的整个执行一个值或零。 漂亮整洁的,是吧?



文章来源: Explain __weak and __strong usage reasons in SDWebImage code