【问题标题】:Attempted to read an unowned reference but object was already deallocated Swift 5尝试读取无主引用但对象已被释放 Swift 5
【发布时间】:2020-02-15 08:34:40
【问题描述】:

我在释放变量时遇到问题:缓存

这是来自教程Reusable Image Cache in Swift

错误:

致命错误:尝试读取无主引用但对象 0x280208080 已被释放 致命错误:尝试读取无主引用但对象 0x280208080 已被释放

代码:

final class ImageLoader {

private let cache = ImageCache()

func loadImage(from url: URL) -> AnyPublisher<UIImage?, Never> {
    if let image = cache[url] {
        return Just(image).eraseToAnyPublisher()
    }
    return URLSession.shared.dataTaskPublisher(for: url)
        .map { UIImage(data: $0.data) }
        .catch { error in return Just(nil) }
        .handleEvents(receiveOutput: {[unowned self] image in
            guard let image = image else { return }
            self.cache[url] = image
        })
        .subscribe(on: DispatchQueue.global(qos: .background))
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}
}

【问题讨论】:

  • 我很确定 ImageLoader 应该是一个单例。但这是一个很好的例子,为什么你永远不应该使用 unowned,你改变你的代码或有人复制它错误,它不仅没有做它应该做的事情,而且它也会崩溃。
  • 这是来自我上面发布的链接的教程,但感谢您的评论。 @Cyber​​beni
  • 是的,这篇文章缺少了这一点。但是最后有一个github链接,里面有完整的源代码,说明作者也认为应该是单例:github.com/sgl0v/OnSwiftWings/blob/…

标签: ios swift xcode


【解决方案1】:

这个错误有一个非常简单的解释:

当 URLSession 完成它的工作时,ImageLoader 的实例并不存在,因为没有人保留对它的引用。当您只是在函数范围变量中创建该实例时,可能会发生这种情况。 (也许在某些功能中,例如 viewDidLoad)。 此崩溃很有用,因为它表示加载程序以错误的方式使用。如果使用弱自身或捕获整个实例,则不会发生崩溃,但是您将拥有很多具有自己缓存的 ImageLoader,其中只有一张图像。因此,它的含义不会有缓存。

为了解决这个问题,在创建 ImageLoader 实例之后,您应该将对它的引用保存在使用它的类/结构变量中,并将其传递给另一个需要相同缓存的消费者。 (依赖注入技术是一个很好的方法)。因此,一个包含一定数量项目的缓存将存在并且可以工作。

或者最简单的方法是创建一个 ImageLoader 的共享实例并仅使用它,因此它还保证它的一个实例具有一个已填充的缓存。

【讨论】:

    【解决方案2】:

    将无主替换为弱

    .handleEvents(receiveOutput: {[weak self] image in
                guard let image = image else { return }
                self.cache[url] = image
            })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2020-08-19
      相关资源
      最近更新 更多