程序猿iOS 开发每天分享优质文章学习资源收集

iOS--SDWebImage处理流程随笔

2019-07-23  本文已影响0人  OXHO

首先附上git地址:https://github.com/SDWebImage/SDWebImage

附上SDWebImage类图:

SDWebImageClassDiagram.png

附上SDWebImage步骤图:

SDWebImageSequenceDiagram.png

核心模块三部分:

1.主要调度类:SDWebImageManager;全部操作都是围绕它为中心;
2.主要缓存类:SDImageCache;
3.主要下载类:SDWebImageDownload;

次要:

4.和UIView相关的类,是对UIKit的扩展,只是方便我们调起Manager里面的功能类;
5.SDImageCacheConfig用于配置缓存;

问题一,SD的大概流程:

1.通过UIImageView+WebCache作为入口,有placeholderImage的情况下,先显示占位图;
2.通过系统类NSMapTable判断当前是否有任务在执行;
⭐️3.重要步骤,如图:

核心方法

问题二,内存缓存模块的实现步骤:

1.SDWebImage实现了磁盘,内存双缓存;
2.内存缓存如何实现的:通过SDMemoryCache类来管理;
3.通过shouldUseWeakMemoryCache的Bool值,来判断是否开启内存缓存;
4.内存缓存有可能存在两份,NSCache和SDMemoryCache,因为NSCache不可控;

问题三,磁盘模块的实现步骤:

1.创建一个目录;
2.为每一个缓存文件生成一个MD5文件名;
3.首先检查内存缓存,再检查磁盘缓存,核心代码:

- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock {
    if (!key) {
        if (doneBlock) {
            doneBlock(nil, nil, SDImageCacheTypeNone);
        }
        return nil;
    }
    
    id<SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
    if (transformer) {
        // grab the transformed disk image if transformer provided
        NSString *transformerKey = [transformer transformerKey];
        key = SDTransformedKeyForKey(key, transformerKey);
    }
    
    // First check the in-memory cache...
    //首先检查内存缓存…
    UIImage *image = [self imageFromMemoryCacheForKey:key];

    if ((options & SDImageCacheDecodeFirstFrameOnly) && image.sd_isAnimated) {
#if SD_MAC
        image = [[NSImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:kCGImagePropertyOrientationUp];
#else
        image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:image.imageOrientation];
#endif
    }

    BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData));
    if (shouldQueryMemoryOnly) {
        if (doneBlock) {
            doneBlock(image, nil, SDImageCacheTypeMemory);
        }
        return nil;
    }
    
    // Second check the disk cache...
    //第二,检查磁盘缓存…
    NSOperation *operation = [NSOperation new];
    // Check whether we need to synchronously query disk
    // 1. in-memory cache hit & memoryDataSync
    // 2. in-memory cache miss & diskDataSync
    BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) ||
                                (!image && options & SDImageCacheQueryDiskDataSync));
    void(^queryDiskBlock)(void) =  ^{
        if (operation.isCancelled) {
            // do not call the completion if cancelled
            return;
        }
        
        @autoreleasepool {
            NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
            UIImage *diskImage;
            SDImageCacheType cacheType = SDImageCacheTypeNone;
            if (image) {
                // the image is from in-memory cache, but need image data
                diskImage = image;
                cacheType = SDImageCacheTypeMemory;
            } else if (diskData) {
                cacheType = SDImageCacheTypeDisk;
                // decode image data only if in-memory cache missed
                diskImage = [self diskImageForKey:key data:diskData options:options context:context];
                if (diskImage && self.config.shouldCacheImagesInMemory) {
                    NSUInteger cost = diskImage.sd_memoryCost;
                    [self.memCache setObject:diskImage forKey:key cost:cost];
                }
            }
            
            if (doneBlock) {
                if (shouldQueryDiskSync) {
                    doneBlock(diskImage, diskData, cacheType);
                } else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        doneBlock(diskImage, diskData, cacheType);
                    });
                }
            }
        }
    };
    
    // Query in ioQueue to keep IO-safe
    if (shouldQueryDiskSync) {
        dispatch_sync(self.ioQueue, queryDiskBlock);
    } else {
        dispatch_async(self.ioQueue, queryDiskBlock);
    }
    
    return operation;
}

问题四,下载模块的实现步骤:

1.SDWebImageDownloader实现了下载管理;围绕NSURLSession实现的;
2.SDWebImageDownloaderOperation实现了生命周期管理,具体任务是它来实现的;
3.核心方法SDWebImageDownloader里的:

- (nullable NSOperation<SDWebImageDownloaderOperation> *)createDownloaderOperationWithUrl:(nonnull NSURL *)url
                                                                                  options:(SDWebImageDownloaderOptions)options
                                                                                  context:(nullable SDWebImageContext *)context {
...
}

4.SDWebImageDownloaderConfig里,SDWebImageDownloaderExecutionOrder枚举,两种情况:

/// Operation execution order
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
    /**
     * Default value. All download operations will execute in queue style (first-in-first-out).
     */
    SDWebImageDownloaderFIFOExecutionOrder,
    
    /**
     * All download operations will execute in stack style (last-in-first-out).
     */
    SDWebImageDownloaderLIFOExecutionOrder
};

FIFOE为先进先出,LIFOE为后进先出;

上一篇下一篇

猜你喜欢

热点阅读