美文网首页
SDWebImage知识点

SDWebImage知识点

作者: 羽裳有涯 | 来源:发表于2018-12-28 11:06 被阅读16次

    SDWebImage的缓存策略

    SDWebImage 的图片缓存默认情况采用的是 MemoryDisk 双重缓存机制。
    下载之前先去Memory中查找图片数据,找到直接返回使用;
    找不到再到Disk中查找图片数据,找到后放入Memory中再返回使用;
    如果Disk中也找不到再去下载图片;
    下载到图片后显示图片并将图片数据存到MemoryDisk中。

    SDWebImageMemory缓存的存取和删除机制

    SDWebImageMemory缓存使用NSCacheSDImageCache类中有一个memCache属性。用这个属性来进行Memory缓存。

    @property (strong, nonatomic) NSCache *memCache;
    

    下面代码用来将图片数据存到Memory中,其中的key是图片的url路径。

    [self.memCache setObject:image forKey:key cost:cost];
    

    下面代码用来获取Memory中的图片数据,其中的key是图片的url路径

    - (UIImage *)imageFromMemoryCacheForKey:(NSString *)key {
        return [self.memCache objectForKey:key];
    }
    

    SDImageCache类还监听了UIApplicationDidReceiveMemoryWarningNotification通知,当收到内存警告时候清除Memory缓存

    [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(clearMemory)
                                                         name:UIApplicationDidReceiveMemoryWarningNotification
                                                       object:nil];
    - (void)clearMemory {
        [self.memCache removeAllObjects];
    }
    

    SDWebImageDisk缓存的存取和删除机制

    SDWebImageDisk缓存图片在/Library/Caches/default/com.hackemist.SDWebImageCache.default文件夹下。且每个图片的存的文件名进行了处理:图片的文件名是图片url路径MD5后的字符串。存取都按照这个新的文件名去操作文件。

    - (NSString *)cachedFileNameForKey:(NSString *)key {
        const char *str = [key UTF8String];
        if (str == NULL) {
            str = "";
        }
        unsigned char r[CC_MD5_DIGEST_LENGTH];
        CC_MD5(str, (CC_LONG)strlen(str), r);
        NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
                              r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
                              r[11], r[12], r[13], r[14], r[15], [[key pathExtension] isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", [key pathExtension]]];
    
        return filename;
    }
    

    Disk缓存有时间限制,默认是一周。

    static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
    

    SDImageCache类监听了通知来删除Disk中过期的图片缓存。
    UIApplicationWillTerminateNotification怎么实现
    1.应用在前台,双击 Home 键 ,终止应用 ,UIApplicationWillTerminateNotification 调用
    2.应用在前台,单击Home 键,进入桌面 , 再终止应用 UIApplicationWillTerminateNotification 不会被调用.

    [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(cleanDisk)
                                                         name:UIApplicationWillTerminateNotification
                                                       object:nil];
    
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(backgroundCleanDisk)
                                                         name:UIApplicationDidEnterBackgroundNotification
                                                       object:nil];
    

    收到通知后,都会进入下面方法。在这个方法中将过期的Disk缓存清除。

    - (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock
    
    

    SWebImage防止一个无效的url多次加载

    SDWebImageManager有个集合属性,这里包含着加载失败的url

    @property (strong, nonatomic) NSMutableSet *failedURLs;
    

    这个集合中保存着加载失败的url,下载之前先判断这个集合是否包含图片的下载url。如果在且下载的策略不是SDWebImageRetryFailed,那个直接返回下载错误,不再进行下载操作。
    下载错误后判断,加入不是一些网络错误,就将这个图片url添加进failedURLs

    if (error.code != NSURLErrorNotConnectedToInternet
                            && error.code != NSURLErrorCancelled
                            && error.code != NSURLErrorTimedOut
                            && error.code != NSURLErrorInternationalRoamingOff
                            && error.code != NSURLErrorDataNotAllowed
                            && error.code != NSURLErrorCannotFindHost
                            && error.code != NSURLErrorCannotConnectToHost) {
                            @synchronized (self.failedURLs) {
                                [self.failedURLs addObject:url];
                            }
                        }
    

    SDWebImage防止同一个url多次加载

    前面已经说过,SDWebImage有缓存策略,再次下载是去缓存中取图片数据,这不就可以避免同一个url多次下载了吗?

    • 当然不可以了。缓存机制只是可以防止已经下载好的图片再次被下载

    假如我同时(几乎同时)去下载同一个url的图片,这是肯定还没有缓存。

    [imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.baidu.comimage/pic/item/1.jpg"]];
    [imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.baidu.comimage/pic/item/1.jpg"]];
    
    

    SDWebImage又是如何处理的? SDWebImageDownloader中有一个可变字典属性。

    @property (strong, nonatomic) NSMutableDictionary *URLCallbacks;
    

    通过下面的代码我们可以看出来字典中key是图片的urlvalue是一个可变数组,数组里面是一个一个的字典,每个字典中保存了下载过程回调和完成回调。每个字典相当于一次下载请求,但是只有第一次的下载请求才会真正去执行下载操作。这样就防止同一个url多次加载。

    /**
     给下载过程添加进度
    
     @param progressBlock 进度Block
     @param completedBlock 完成Block
     @param url url地址
     @param createCallback nil
     @return 返回SDWebImageDownloadToken。方便后面取消
     */
    - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
                                               completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
                                                       forURL:(nullable NSURL *)url
                                               createCallback:(SDWebImageDownloaderOperation *(^)())createCallback {
        // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
        if (url == nil) {
            if (completedBlock != nil) {
                completedBlock(nil, nil, nil, NO);
            }
            return nil;
        }
    
        __block SDWebImageDownloadToken *token = nil;
    
        dispatch_barrier_sync(self.barrierQueue, ^{
            //看是否当前url是否有对应的Operation图片加载对象
            SDWebImageDownloaderOperation *operation = self.URLOperations[url];
            //如果没有,则直接创建一个。
            if (!operation) {
                //创建一个operation。并且添加到URLOperation中。
                operation = createCallback();
                self.URLOperations[url] = operation;
    
                __weak SDWebImageDownloaderOperation *woperation = operation;
                //设置operation操作完成以后的回调
                operation.completionBlock = ^{
                  SDWebImageDownloaderOperation *soperation = woperation;
                  if (!soperation) return;
                  if (self.URLOperations[url] == soperation) {
                      [self.URLOperations removeObjectForKey:url];
                  };
                };
            }
            id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
            token = [SDWebImageDownloadToken new];
            token.url = url;
            token.downloadOperationCancelToken = downloadOperationCancelToken;
        });
    
        return token;
    }
    

    在图片下载完成或者取消下载,根据urlURLCallbacks中的数组移除。

    http 304 Not Modified

    SDWebImage也对304这种情况做了相应了处理。 假如你读过SDWebImage源码,该会对这个有点了解吧!

    //This is the case when server returns '304 Not Modified'. It means that remote image is not changed.
    //In case of 304 we need just cancel the operation and return cached image from the cache.  
    
    • 加入返回304直接取消下载操作并从缓存中返回图片数据。

    相关文章

      网友评论

          本文标题:SDWebImage知识点

          本文链接:https://www.haomeiwen.com/subject/wrfslqtx.html