I've been trying to figure out this one for a bit now, so while trying to load an image remotely and I am running into the domain error. So here is what I get from the console:
Task <95AAB48F-8670-4E1D-AA29-21D47E0EE069>.<5> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=http://gba.ergoware.io/cache/content/topstory/ergo_news_01.png, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=http://gba.ergoware.io/cache/content/topstory/ergo_news_01.png}
Here is the class calling the image from the site:
// MARK: Remote Image Loading
class ImageLoader: ObservableObject {
@Published var image: UIImage?
private let url: URL
private var cancellable: AnyCancellable?
private var cache: ImageCache?
init(url: URL, cache: ImageCache? = nil) {
self.url = url
self.cache = cache
}
func load() {
if let image = cache?[url] {
self.image = image
return
}
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { UIImage(data: $0.data) }
.replaceError(with: nil)
.handleEvents(receiveOutput: { [weak self] in self?.cache($0) })
.receive(on: DispatchQueue.main)
.assign(to: \.image, on: self)
}
private func cache(_ image: UIImage?) {
image.map { cache?[url] = $0 }
}
func cancel() {
cancellable?.cancel()
}
}
struct AsyncImage<Placeholder: View>: View {
@ObservedObject private var loader: ImageLoader
private let placeholder: Placeholder?
init(url: URL, placeholder: Placeholder? = nil, cache: ImageCache? = nil) {
loader = ImageLoader(url: url, cache: cache)
self.placeholder = placeholder
}
var body: some View {
image
.onAppear(perform: loader.load)
.onDisappear(perform: loader.cancel)
}
private var image: some View {
Group {
if loader.image != nil {
Image(uiImage: loader.image!)
.resizable()
} else {
placeholder
}
}
}
}
protocol ImageCache {
subscript(_ url: URL) -> UIImage? { get set }
}
struct TemporaryImageCache: ImageCache {
private let cache = NSCache<NSURL, UIImage>()
subscript(_ key: URL) -> UIImage? {
get { cache.object(forKey: key as NSURL) }
set { newValue == nil ? cache.removeObject(forKey: key as NSURL) : cache.setObject(newValue!, forKey: key as NSURL) }
}
}
// MARK: Image Cache
struct ImageCacheKey: EnvironmentKey {
static let defaultValue: ImageCache = TemporaryImageCache()
}
extension EnvironmentValues {
var imageCache: ImageCache {
get { self[ImageCacheKey.self] }
set { self[ImageCacheKey.self] = newValue }
}
}
So how this is set up is, my interface calls the images, and for certain images like the user's profile image or achievement badges, the image will be cached during the session to prevent multiple request for the same image and cutting down on load time and server traffic in the long run.
Any help would be appreciated! Thanks!