如何解决打破 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
的实例不同的对象。对于您在问题中发布的代码,参考文献如下所示:
假设我们实现 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))
}
}
}
}
然后引用看起来像这样:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。