I have a problem with a deallocation of a variable: cache
This is from the tutorial Reusable Image Cache in Swift
Error:
Fatal error: Attempted to read an unowned reference but object 0x280208080 was already deallocated Fatal error: Attempted to read an unowned reference but object 0x280208080 was already deallocated
Code:
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()
}
}
This error has a pretty simple explanation:
by the time URLSession is finishing its work, the instance of ImageLoader does not exist, because nobody keeps a reference to it. It may happen when you just create that instance in function scope variable. (Maybe in some function like viewDidLoad). This crash is useful, as it says that loader is using in the wrong way. In case of usage of weak self or capturing the whole instance, the crash will not happen, but you will have a lot of ImageLoaders with its own caches with one image there. Thus there would be no caching in its meaning.
To solve that, after the creation of ImageLoader instance, you should keep the reference to it in a class/struct variable which is consuming it and pass it to another consumer, who needs the same cache. (a dependency injection technic is a good approach for that). Thus one cache with some amount of items will exist and works.
Or the simplest way is to make a shared instance of ImageLoader and use it only, thus it also guaranties one instance of it with one filled cache.
replace unowned to weak
.handleEvents(receiveOutput: {[weak self] image in
guard let image = image else { return }
self.cache[url] = image
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With