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!
This error happens due to attached .onDisappear
to placeholder, so when real image has loaded and assigned to published property the view is refreshed, so placeholder is removed, so cancel is called on completed but not yet finished data task, so the log.
Here is simplest fix. Tested with Xcode 11.4 / iOS 13.4.
var body: some View {
image
.onAppear(perform: loader.load)
.onDisappear {
if self.loader.image == nil { // cancel only if not loaded yet
self.loader.cancel()
}
}
}
Hello, Try to Allow Arbitrary loads in info.plist
file Learn More by checking out this answer: https://stackoverflow.com/a/40299837/7443052
Regards, David
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.