ibireme / YYWebImage

Asynchronous image loading framework.
MIT License
3.56k stars 615 forks source link

关于SDWebImageRefreshCached的功能是否真的能够实现图片刷新? #104

Closed MichaelHuyp closed 8 years ago

MichaelHuyp commented 8 years ago

大神。。我现在遇到这样一个需求 我们公司后台返回一张图片的url 然后在此url的基础上 url不变只在PC端更改图片源。。 但是当我用SDWebImageRefreshCached这个选项的时候 在手机端并没有更换图片。。 上网查了很多资料 并且尝试用YYWebImage的YYWebImageOptionRefreshImageCache 发现也并不是我想要的那种效果。。。 在https://github.com/rs/SDWebImage/issues/1305 此issues上发现是不是我们公司的后台也需要在图片的响应头中配置一些参数才能达到客户端同步刷新的效果。。。 迷茫了 希望大神就这个问题指点一二

MichaelHuyp commented 8 years ago

经过测试发现。。YYWebImage的YYWebImageOptionRefreshImageCache会忽略缓存。。 每次都重新下载 我现在想要的效果就是 服务器端图片源更新(图片URL不变)。。 才去下载这张图片并把图片放入缓存中(最好把被替换的图片缓存再删掉 ^ ^)。。 当图片源没有变化的时候就从缓存中拿。。 不知道YYWebImage有没有做类似的功能 。。。上网查了好多资料 有说让服务器端支持cache-control的说法,有说根据图片的response header中的ETag与Last-Modified 判断的。。。

ibireme commented 8 years ago

那可能需要你来手动实现这个功能了,毕竟对那些 header 的特殊处理不是通用需求。

另外,对于图片这种资源,非常不建议服务器这么做。

MichaelHuyp commented 8 years ago

(⊙o⊙)哦 那我去跟后台沟通一下吧 让他换图片的时候顺便换下url 。。 其实这个需求也不算特殊吧。。 希望大神有空可以给YYKit加上这个功能 让YYKit的框架更牛~~

ibireme commented 8 years ago

ETag 具体含义是由服务端来定义的,这个不能通用。另外,如果利用 header 来做判断的话,那每次设置图片都需要发起 http 请求,那这样本地缓存的好处就被削弱不少了。

applejian commented 7 years ago

之前改了sdwebimage版的,后来更换到yy 这次也稍微调整了下让yy也支持 cache-control,例子是在yydemo中改写的,贴出关键部分的代码如下: ` //测试地址 NSString avatar = @"http://img.dahe.cn/2016/11-29/107847530.jpg"; //加上时间戳避免手机网络出现的cdn缓存问题 avatar = [avatar stringByAppendingFormat:@"?t=%f",[[NSDate date] timeIntervalSince1970]]; NSURL avatarUrl = [NSURL URLWithString:avatar];

__weak typeof(_profileView) profileView = _profileView; [_profileView.avatarView setImageWithURL:avatarUrl //profileImageURL placeholder:nil options:YYWebImageOptionProgressiveBlur | YYWebImageOptionSetImageWithFadeAnimation | YYWebImageOptionRefreshImageCache manager:[WBStatusHelper avatarImageManager] //< 圆角头像manager,内置圆角处理 progress:nil transform:nil completion:^(UIImage _Nullable image, NSURL _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError _Nullable error) { //最好加上这句 取不到或者报错了设置读缓存的数据 或者 placeholder等 if (error / && [error code] == 304 /) {//没有最新的 表示从缓存读取 .. YYWebImageManager imageManager = [WBStatusHelper avatarImageManager];// 圆角头像 矩形裁剪 cache-control [[imageManager cache] getImageForKey:[imageManager cacheKeyForURL:url] withType:YYImageCacheTypeAll withBlock:^(UIImage * _Nullable image, YYImageCacheType type) { if (image) { profileView.avatarView.image = image; }else{// set .. placeholder

                                      }
                                  }];

                                  return ;
                              }

                          }];

`

`+ (YYWebImageManager )avatarImageManager { static YYWebImageManager manager; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSString path = [[UIApplication sharedApplication].cachesPath stringByAppendingPathComponent:@"weibo.avatar"]; YYImageCache cache = [[YYImageCache alloc] initWithPath:path]; cache.diskCache.customFileNameBlock = ^(NSString imgKey){ if (!imgKey) return imgKey; YYWebImageManager _imageManager = [WBStatusHelper avatarImageManager]; imgKey = [_imageManager cacheKeyForURL:[NSURL URLWithString:imgKey]];

        return [imgKey md5String];
    };

    manager = [[YYWebImageManager alloc] initWithCache:cache queue:[YYWebImageManager sharedManager].queue];

    manager.sharedTransformBlock = ^(UIImage *image, NSURL *url) {
        if (!image) return image;

        // 非正方形的图片 进行裁剪处理
        CGSize size = [image size];
        CGFloat aspectLine = MIN(size.width, size.height);

        if (size.width != size.height) {
            UIImage * cropedImage = [image imageByResizeToSize:CGSizeMake(aspectLine, aspectLine) contentMode:UIViewContentModeScaleAspectFill];
            return [cropedImage imageByRoundCornerRadius:aspectLine];
        }

        return [image imageByRoundCornerRadius:aspectLine]; // a large value
    };

    manager.cacheKeyFilter = ^(NSURL *url){

        NSString * imageKey = [url absoluteString];

        NSRange range = [imageKey rangeOfString:@"?"];
        if (range.location != NSNotFound) {
            imageKey = [imageKey substringToIndex:range.location];
        }

        return imageKey;
    };

    //prepare cache-control for server
    manager.headersFilter = ^NSDictionary *(NSURL *url, NSDictionary *headers) {
        YYWebImageManager * _imageManager = [WBStatusHelper avatarImageManager];

        // subString ? ...
        NSString *imgKey = [_imageManager cacheKeyForURL:url];// url

        YYDiskCache *diskCache = _imageManager.cache.diskCache;
        //外部无法直接获取到YYKVStorage对象 所以 valueForKey... 这里其实还可以通过c直接读取对应缓存过的本地文件时间属性,经测试发现速度过慢,与YYKVStorage访问数据库速度相差有6倍
        YYKVStorage * vs = [diskCache valueForKey:@"_kv"];
        dispatch_semaphore_t _lock = [diskCache valueForKey:@"_lock"];

        dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
        YYKVStorageItem *item = [vs getItemInfoForKey:imgKey];
        dispatch_semaphore_signal(_lock);
        if (item) {
            int time = item.modTime;
            if (time > 0) {

                // format date... begin
                struct tm *timeinfo;
                char buffer[128];
                //    time_t rawtime = interval;// - [[NSTimeZone localTimeZone] secondsFromGMT];
                //    timeinfo = gmtime(&rawtime);
                time_t rawtime = time - [[NSTimeZone localTimeZone] secondsFromGMT];
                timeinfo = localtime(&rawtime);
                strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T GMT", timeinfo);
                NSString * lastModifiedStr = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
                // format date... end

                lastModifiedStr = lastModifiedStr.length > 0 ? lastModifiedStr : @"";
                // set into header
                NSMutableDictionary *mutableHeaders = [headers mutableCopy];
                [mutableHeaders setValue:@"0" forKey:@"Age"];
                [mutableHeaders setValue:lastModifiedStr forKey:@"If-Modified-Since"];
                [mutableHeaders setValue:@"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/*,*/*;q=0.8" forKey:@"Accept"];

                return mutableHeaders;

            }
        }

        return headers;
    };

});
return manager;

}`

改写的是 WBStatusHelper 中 avatarImageManager 这个方法,这样图像园角cache-control 都能直接连起来用了

sdwebimage header 同理 如果有需要@me

如果以上方案有更好的还请大家提供建议