微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

打破 Swift 闭包保留圈而不弱显式捕获

如何解决打破 Swift 闭包保留圈而不弱显式捕获

下面的Swift by Sundell文章指出,在某些情况下,对类内部的属性进行显式捕获就足以打破引用保留循环。这是确切的例子:

class ImageLoader {
    private let cache = Cache<URL,Image>()

    func loadImage(
        from url: URL,then handler: @escaping (Result<Image,Error>) -> Void
    ) {
        // Here we capture our image loader's cache without
        // capturing 'self',and without having to deal with
        // any optionals or weak references:
        request(url) { [cache] result in
            do {
                let image = try result.decodedAsImage()
                cache.insert(image,forKey: url)
                handler(.success(image))
            } catch {
                handler(.failure(error))
            }
        }
    }
}

这样您就可以避免后验空检查以提高可读性。像下面的article

中解释的那样,它对组合很有用

我不明白为什么这会打破保留圈,因为 [缓存] 捕获仍然是对 ImageLoader 属性的强引用

解决方法

[cache] capture 仍然是对 ImageLoader 属性的强引用,但不保留自身。这延长了缓存对象的生命周期,同时请求(url)回调块持有对缓存的强引用 - 甚至可以在回调块完成之前释放 self ,并且缓存可以停留更长的时间。>

如果存在强引用循环 A->B 和 B->A,或 A->B->C 和 C->A 等,您只会得到一个保留循环。这里我们有 A->Cache 和A 创建但随后交给 url 会话的某个块保留了缓存。所以这不是一个循环A->缓存和请求(url)完成处理程序也->缓存。 A 可以自由释放,这意味着缓存引用计数将从 2 变为 1,并且在 url 会话下载时仍然存在。

,

cache 属性引用 Cache 的实例,它是与 ImageLoader 的实例不同的对象。对于您在问题中发布的代码,参考文献如下所示:

diagram showing both the instance of ImageLoader and the completion closure pointing at the instance of Cache

假设我们实现 loadImage 而不将 cache 放入捕获列表:

class ImageLoader {
    private let cache = Cache<URL,Image>()

    func loadImage(
        from url: URL,then handler: @escaping (Result<Image,Error>) -> Void
    ) {
        request(url) { result in
                    // ^^^^^^^^^ no capture list
            do {
                let image = try result.decodedAsImage()
                self.cache.insert(image,forKey: url)
             // ^^^^^ we have to explicitly reference self instead
                handler(.success(image))
            } catch {
                handler(.failure(error))
            }
        }
    }
}

然后引用看起来像这样:

diagram showing the completion closure pointing at the instance of ImageLoader,and the instance of ImageLoader pointing at the instance of Cache

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。