SDWebImage / SDWebImageSwiftUI

SwiftUI Image loading and Animation framework powered by SDWebImage
https://sdwebimage.github.io/SDWebImageSwiftUI
MIT License
2.14k stars 219 forks source link

Custom loader doesn't work #201

Closed pfcstyle closed 2 years ago

pfcstyle commented 2 years ago

I'm using a third-party framework named ArcGIS and I can't get authentication token from the framework, so I have to custom a image loader to use its download method to download image.

The code is below:

class AGSSDImageLoader: NSObject, SDImageLoader{

    static var shared: AGSSDImageLoader = AGSSDImageLoader()

    func canRequestImage(for url: URL?) -> Bool {
        print("canRequestImage")
        return true
    }

    func requestImage(with url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]?, progress progressBlock: SDImageLoaderProgressBlock?, completed completedBlock: SDImageLoaderCompletedBlock? = nil) -> SDWebImageOperation? {
        print("requestImage")
        guard let url = url else { return nil }
        let agsO = APIService.shared.AGSDownload(url: url.absoluteString) { result in
            switch result{
            case .success(let data):
                let image = SDImageLoaderDecodeImageData(data, url, options, context)
                completedBlock?(image, data, nil, true)
                break
            case .failure(let error):
                completedBlock?(nil, nil, error, true)
                break
            }
        }
        return agsO
    }

    func shouldBlockFailedURL(with url: URL, error: Error) -> Bool {
        print("shouldBlockFailedURL")
        return false
    }

}

And I add the loader in func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool:

SDImageLoadersManager.shared.loaders = [AGSSDImageLoader.shared, SDWebImageDownloader.shared]
SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared

There is no any output from the AGSSDImageLoader, and image is loaded like that loaders contains SDWebImageDownloader only.

Thanks!

dreampiggy commented 2 years ago

@pfcstyle Try to debug on this line of code SDWebImageManger.m:375 to see whether this is a BUG or something wrong :

image

And for your use case, actually you can use another feature request modifier, to override the URLRequest's headers (to append your access token).

pfcstyle commented 2 years ago

Thank you @dreampiggy . I found why it doesn't work.

  1. I set defaultLoader after setting cacheKeyFilter. SDWebImageManager.shared call its init method to set imageLoader property, but defaultImageLoader is NULL this time. So we must set defaultImageLoader before SDWebImageManager firstly init.

       // bad code
        SDWebImageManager.shared.cacheKeyFilter = SDWebImageCacheKeyFilter(block: { (url) -> String? in
            return url.getSDCacheKey()
        })
    
        SDImageLoadersManager.shared.loaders = [AGSSDImageLoader.shared, SDWebImageDownloader.shared]
        SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared
  2. The order is important. The later added loader will have the highest priority
//work code
SDImageLoadersManager.shared.addLoader(AGSSDImageLoader.shared)
SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared

SDWebImageManager.shared.cacheKeyFilter = SDWebImageCacheKeyFilter(block: { (url) -> String? in
    return url.getSDCacheKey()
})

By the way, request modifier is not suitable for me, because I can't get my access token directly. Thanks for your advice.