SDWebImageSwiftUI
SDWebImageSwiftUI copied to clipboard
Is it possible to preserve images in cache even in case of a HTTP 300/400/500 response from server?
I'm using SDWebImage
in order to preserve data bandwidth with .refreshCached
in order to update images from time to time:
WebImage(url: url, options: .refreshCached, options: .refreshCached)
This works great even if the network is down, images are served from cache.
However, if the URL of the image returns 300/400/500, etc... - which may happen - SDWebImage erased the image from cache and no image is displayed. This is not a desirable behaviour as 1) servers can be down temporarily for maintenance, 2) public WiFi networks return 302 Moved for unauthenticated users, etc - I would prefer keeping images in cache until a new valid image is downloaded.
Is that possible?
Why not use SDWebImageDownloadConfig.acceptableStatusCodes
?
https://sdwebimage.github.io/documentation/sdwebimage/sdwebimagedownloaderconfig/acceptablestatuscodes
You can read documentation firstly and search for the result
When you config acceptableStatusCodes
to nil, behaves like below:
- When server down and return error HTTP response, although we don't mark URLSession fail and continue to run
- Because of the returned HTTP body data, can not decode to any image format, then the DownloadOperation mark as failed with error code .badimagedata
- From top level, sd_setImage API get the NSError and you can do logic on it
@dreampiggy Thanks for your response. Interestingly, although I added the following code to my app:
import SDWebImage
import SDWebImageSwiftUI
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
SDWebImageDownloader.shared.config.acceptableStatusCodes = [200]
return true
}
}
Still an HTTP 403
status on a resource causes this image to show up from cache on load, but disappear in about 5 seconds (I guess when the HTTP call is unsuccessful after a few attempts):
struct ContentView: View {
var body: some View {
WebImage(url: URL(string: "<any_http_403_resource>")!, options: .refreshCached)
.resizable()
}
}
Any ideas what is wrong with my setup? Thanks!
This is NSIndexSet. Your "[200]" menas only HTTP 200 will treat as success.
I menas you provide a IndexSet with range like [200, 600) or something
Maybe you misunderstand that refreshCache means.
That strange option behave:
- First read image from cache and callback to set image on View
- When network finished, check whether the download image is equal to previous callback image
- If same, do nothing and no second callback
- If not same, callback second with the new image (note new image will be nil if download failed)
Maybe you misunderstand that refreshCache means.
That strange option behave:
- First read image from cache and callback to set image on View
- When network finished, check whether the download image is equal to previous callback image (we use context option dict to keep a strong reference to that previous image🥲 see hack:https://sdwebimage.github.io/documentation/sdwebimage/sdwebimagecontextoption/loadercachedimage )
- If same, do nothing and no second callback
- If not same, callback second with the new image (note new image will be nil if download failed)
For you case, you can either:
- Use another feature called .avoidAutoSetImage and manual set image and filter this second callback
- Use responseModifier API, to read the previous image from cache again (ugly hack) and return, so the new image and previous inage will be the same and no second callback triggered (...)
- Feature request: Hack that context option (.loaderCachedImage) which keep the previous image, set it to nil when network download failed. Or just write another wrapper SDImageDownloader. Pseudocode
class MyImageLoader : SDImageLoaderProtocol {
func loadImage(with: url, callback) {
let loadedImage = context[.loaderCachedImage]
SDImageDownloader.shared.loadImage(with: url) { image, data, error in
if error && loadedImage {
callback(loadedImage, nil, NSError(domain: SDWebImageErrorDomain code: .cacheNotModified))
return
}
callback(image, data, error)
}
}
}
Is this feature really useful in general ?
I think that in general it would be useful to have a built-in option to keep cached images as long as there is a valid new version of them. If the remote server containing the images is broken for whatever reason (developer mistake, hardware issue) and returns invalid response codes such as 403, 404, 500, ... the user of the mobile app would still see the correct image.
Seems a feature request. Maybe we can create a issue in https://github.com/SDWebImage/SDWebImage/issues and reference this.
It's not hard to implements, but need a new options like SDWebImageRefreshCachedIgnoreError
, or another global config to avoid huge codebase changes ?
I like the .refreshCachedIgnoreError
option. Should we let people vote before I create the new request?
It's OK to fire issue first. The detail API name actually we can talk in PR.