美文网首页
六、SDWebImage源码解读SDImageCache(二)

六、SDWebImage源码解读SDImageCache(二)

作者: 小强简书 | 来源:发表于2018-02-06 15:13 被阅读27次

    上一篇我们主要介绍了下SDImageCache的方法的含义和实现,这篇主要介绍SDImageCache的重点方法。

    一、这个方法在缓存中查询对应key的图片信息 包含image,diskData以及缓存的类型返回一个NSOperation

    - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {
        if (!key) { //若key == nil ,直接返回,判空
            if (doneBlock) {
                doneBlock(nil, nil, SDImageCacheTypeNone);
            }
            return nil;
        }
    
        // First check the in-memory cache... 第一步:从内存中取出image
        UIImage *image = [self imageFromMemoryCacheForKey:key]; //从缓存当中取出image
        if (image) {
            NSData *diskData = nil;
            if (image.images) {//如果是gif图像,这从disk中提取完整图像
                diskData = [self diskImageDataBySearchingAllPathsForKey:key];
            }
            if (doneBlock) {
                doneBlock(image, diskData, SDImageCacheTypeMemory);
            }
            return nil;
        }
    
        NSOperation *operation = [NSOperation new];
        dispatch_async(self.ioQueue, ^{ // 异步
            if (operation.isCancelled) { //如果当前operation 为caneclled 直接返回
                // do not call the completion if cancelled
                return;
            }
    
            @autoreleasepool {
                //到这里说明已经来到磁盘缓存区获取 然后回调结束
                NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
                UIImage *diskImage = [self diskImageForKey:key];
                if (diskImage && self.config.shouldCacheImagesInMemory) {//如果有值,并且为shouldCacheImagesInMemory的时候将image缓存起来
                    NSUInteger cost = SDCacheCostForImage(diskImage); //获取图片字节数
                    [self.memCache setObject:diskImage forKey:key cost:cost];
                }
    
                if (doneBlock) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
                    });
                }
            }
        });
    
        return operation;
    }
    
    

    二、应用进入后台的时候,调用这个方法 然后清除过期图片

     [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(clearMemory)
                                                         name:UIApplicationDidReceiveMemoryWarningNotification
                                                       object:nil];
    
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(deleteOldFiles)
                                                         name:UIApplicationWillTerminateNotification
                                                       object:nil];
    
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(backgroundDeleteOldFiles)
                                                         name:UIApplicationDidEnterBackgroundNotification
                                                       object:nil];
    
    - (void)backgroundDeleteOldFiles {
        Class UIApplicationClass = NSClassFromString(@"UIApplication");
        if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) {
            return;
        }
        UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)];
        __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
            // Clean up any unfinished task business by marking where you
            // stopped or ending the task outright.
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];
    
        // Start the long-running task and return immediately.
        [self deleteOldFilesWithCompletionBlock:^{
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];
    }
    

    方法通过向iOS申请,在后台完成一个Long-Running Task任务,当一个 iOS 应用被送到后台,它的主线程会被暂停。你用 NSThread 的 detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。
    如果你想在后台完成一个长期任务,就必须调用 UIApplication 的 beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 借点时间。
    默认情况下,如果在这个期限内,长期任务没有被完成,iOS 将终止程序。
    怎么办?可以使用 beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 再借点时间。经过证明,即使时执行Long-Running Task 任务,当程序被调到后台后,也是有时间限制的。一般为10分总(600s)

    三、SDImageCacheConfig,缓存配置对象,包含所有配置项(解压缩图像,iCloud备份, 最长缓存时间,等等)我们自己在封装类的时候,应该学习这种方式

    /**
     * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
     * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
     * 解压缩图像下载和缓存可以提高性能,但会消耗大量的内存。
     * 默认为yes。如果由于内存消耗过多而发生崩溃,请将此设置为NO。
     */
    
    @property (assign, nonatomic) BOOL shouldDecompressImages;
    
    /**
     * disable iCloud backup [defaults to YES]
     是否禁用iCloud备份, 默认为YES
     */
    @property (assign, nonatomic) BOOL shouldDisableiCloud;
    
    /**
     * use memory cache [defaults to YES]
     是否缓存到内存中,默认为YES
     */
    @property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
    
    /**
     * The reading options while reading cache from disk.
     * Defaults to 0. You can set this to mapped file to improve performance.
      最大的缓存不过期时间, 单位为秒,默认为一周的时间
     */
    @property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;
    
    /**
     * The maximum length of time to keep an image in the cache, in seconds.
     最长缓存时间 默认为1周
     */
    @property (assign, nonatomic) NSInteger maxCacheAge;
    
    /**
     * The maximum size of the cache, in bytes.
     最大的缓存的size,单位是字节
     */
    @property (assign, nonatomic) NSUInteger maxCacheSize;
    
    

    四、NSCache

    NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存,它与集合的不同如下:

    1. NSCache具有自动删除的功能,以减少系统占用的内存;
    2. NSCache是线程安全的,不需要加线程锁;
    3. 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)。

    添加到缓存

    - (nullable ObjectType)objectForKey:(KeyType)key;
    - (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
    - (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
    

    删除缓存指定key

    - (void)removeObjectForKey:(KeyType)key;
    

    删除全部

    - (void)removeAllObjects;
    

    totalCostLimit:设置缓存占用的内存大小,并不是一个严格的限制,当总数超过了totalCostLimit设定的值,系统会清除一部分缓存,直至总消耗低于totalCostLimit的值

    countLimit:设置缓存对象的大小,这也不是一个严格的限制。

    代理方法

    • (void)cache:(NSCache *)cache willEvictObject:(id)obj;
      第一个参数是当前缓存(NSCache),不要修改该对象;
      第二个参数是当前将要被清理的对象,如果需要存储该对象,可以在此操作(存入Sqlite or CoreData);

    五、计算图片大小(内联函数)

    FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
    #if SD_MAC
        return image.size.height * image.size.width;
    #elif SD_UIKIT || SD_WATCH
        return image.size.height * image.size.width * image.scale * image.scale;
    #endif
    }
    

    相关文章

      网友评论

          本文标题:六、SDWebImage源码解读SDImageCache(二)

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