Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explain __weak and __strong usage reasons in SDWebImage code

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);
    }
}
like image 366
Ed Chin Avatar asked Feb 16 '13 07:02

Ed Chin


1 Answers

The downloadWithUrl: method might take a long time. In that time, the user might decide to navigate away, eliminating the need for the SDWebImage object. To facilitate early cleanup of the object, the outer self reference is weak. This way, downloadWithUrl won't prevent the SDWebImage from being deallocated.

Of course, if you actually want to work with self, you need a strong reference. So, the on-completion block of downloadWithUrl grabs a strong reference to self. If the object goes away in this time, sself will be nil. Otherwise, it will be a valid strong reference, indicating that the SDWebImage object is still around, and the object will finish its work at this time.

like image 173
nneonneo Avatar answered Sep 19 '22 22:09

nneonneo