前言
在 SDWebImage 中,有一个 SDWebImageCacheKeyFilter 的协议可以让开发者来自定义 CacheKey,而不是使用默认的 url 当 key。
下面的代码示例来自官方:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL *url) {
url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
return [url absoluteString];
};
// Your app init code...
return YES;
}
遇到的问题
我是开发主项目中的一个模块,自己对 sd 的调用进行了一个简单的包装:
- (void)custom_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setImageWithURL:url placeholderImage:placeholder options:SDWebImageAllowInvalidSSLCertificates context:nil];
}
开发中,就是正常调用上面的方法去异步加载图片。但是代码提交测试后,测试反馈了一个 Bug:在主工程的设置页面,修改用户头像后,我开发的模块中,所有用 sd 加载的图片都会变成用户的新头像。
在我确定我这边代码没有什么问题后,就查看了主工程的代码。发现了主工程在用户头像修改后会自定义 SDWebImage 的 filterCacheKey:
NSString *headUrl = [NSString stringWithFormat:@"customprotocol://%@",@"image"];
SDWebImageCacheKeyFilter *cacheKey = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) {
return headUrl;
}];
[[SDWebImageManager sharedManager] setCacheKeyFilter:cacheKey];
上面的代码虽然是按照官方示例写的。但它会将所有 sd 缓存图片的 key 都替换成 headUrl。
通过 sd 的源码也可以验证这一点:
当全局修改 filter 后,我的模块中图片缓存的 key 也会变成修改的 filter,这也就造成了模块中的图片全部变成用户头像的问题。
解决方案
解决方案如下:
SDWebImageCacheKeyFilter *filter = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) {
return url.absoluteString;
}];
SDWebImageContext *context = @{ SDWebImageContextCacheKeyFilter: filter };
[self sd_setImageWithURL:url placeholderImage:placeholder options:SDWebImageAllowInvalidSSLCertificates context:context];
上述代码的作用:重新将 absoluteString 这是为图片的 cacheKey,并绑定到 context 上。这样,图片的本身 URL 的地址就会成图片的 cacheKey 了。
使用 context 而不适用 sharedManager 的原因如下:sharedManager 为单例,修改它的属性会影响整个项目。对于多模块的项目会造成不可预料的问题。
所以,在多模块项目中,对单例的修改,我们应该慎之又慎。