【问题标题】:Explain __weak and __strong usage reasons in SDWebImage code解释 SDWebImage 代码中的 __weak 和 __strong 使用原因
【发布时间】:2014-11-26 23:18:42
【问题描述】:

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

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

我确信这段代码很好,很优雅,所以我试图理解它。如果“self”在块运行之前不再存在,弱自引用将归零。当块运行时,强引用也将设置为零。因此,它会知道杀死其余的操作,因为 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);
    }
}

【问题讨论】:

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


    【解决方案1】:

    downloadWithUrl: 方法可能需要很长时间。在那个时候,用户可能会决定离开,从而不再需要SDWebImage 对象。为了便于对象的早期清理,外部self 引用是弱的。这样,downloadWithUrl 不会阻止 SDWebImage 被释放

    当然,如果你真的想使用self,你需要一个强有力的参考。因此,downloadWithUrl 的完成块获得了对self 的强引用。如果对象在这段时间内消失,sself 将是nil。否则,它将是一个有效的强引用,表明SDWebImage 对象仍然存在,并且该对象将在此时完成它的工作。

    【讨论】:

    • 另一个绝妙的答案。谢谢 nneonneo。
    • 这不仅仅是“为了便于早期清理对象”。它完全有利于对象的清理——否则会有一个保留周期——self 通过关联引用保留operationoperation 保留该块。如果块保留self,这将是一个循环。
    【解决方案2】:

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

    不,你想太多了。 __weak 存储限定符就是这样:一个限定符。 __weak 的对象是明确未保留的,但如果从强变量分配,它们不仅会自动设置为 nil。事实上,这会破坏弱变量的目的!

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

    检查实际上是不必要的,因为运行时将消息解析为 nil 到 nil(尽管如此,它可能对以后的实现很重要,谁知道呢)。你是正确的:如果没有那个“弱到强”的小舞蹈,那么 self 将被块保留,有可能创造一个非常讨厌的保留循环。这就是我可以开始将这一切联系在一起的地方:

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

    【讨论】:

    • 您的最后一段非常有帮助。谢谢 CodaFi。
    • 我不明白这句话:“......我们回到一个强大的自我变量,所以弱的自我变量被释放”。 sself 是否在那里创建一个强引用以确保 wself 在另一个线程执行块的过程中不会被释放?
    • 有点。如果您不重新分配块中的强变量,它可能会从我们下面释放并在块执行过程中设置为 nil。通过分配给 strong ,您可以保证在整个块的整个执行期间 self 不是 nil 或 nil。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 2017-03-23
    相关资源
    最近更新 更多