• SDWebImage源码分析


    1 - (NSInteger)maxConcurrentDownloads {
    2     return _downloadQueue.maxConcurrentOperationCount;
    3 }

     SDWebImageManager -- 单例

     1 - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {

    1.1 id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:

    ^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL)  

     1.2 [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; 

    SDWebImageManager
    1
    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url 2 options:(SDWebImageOptions)options 3 progress:(SDWebImageDownloaderProgressBlock)progressBlock 4 completed:(SDWebImageCompletionWithFinishedBlock)completedBlock { 25 __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new]; 41 @synchronized (self.runningOperations) { 42 [self.runningOperations addObject:operation]; 43 } 44 NSString *key = [self cacheKeyForURL:url]; 45 46 operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key
                                             done:
    ^(UIImage *image, SDImageCacheType cacheType)
         {
    47 if (operation.isCancelled) {
    49
    [self.runningOperations removeObject:operation]; 52 return; 53 } 55 if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))
            {
    56 if (image && options & SDWebImageRefreshCached) { 57 dispatch_main_sync_safe(^{ 58 // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image 59 // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. 60 completedBlock(image, nil, cacheType, YES, url); 61 }); 62 } 79 id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) { 80 if (weakOperation.isCancelled) { 81 // Do nothing if the operation was cancelled 82 // See #699 for more details 83 // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data 84 } 85 else if (error) {
    88
    completedBlock(nil, error, SDImageCacheTypeNone, finished, url); 94             [self.failedURLs addObject:url];
    97
    } 98 else { 99 BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); 101 if (options & SDWebImageRefreshCached && image && !downloadedImage) { 102 // Image refresh hit the NSURLCache cache, do not call the completion block 103 } 104 // NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it 105 else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { 106 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 107 UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; 109 if (transformedImage && finished) { 110 BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; 111 [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk]; 112 }
    116 completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
    119 }); 120 } 121 else { 122 if (downloadedImage && finished) { 123 [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk]; 124 }
    128 completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
    131 } 132 } 134 if (finished) {
    136 [self.runningOperations removeObject:operation];
    138 } 139 }]; 140 operation.cancelBlock = ^{ 141 [subOperation cancel];
    144 [self.runningOperations removeObject:weakOperation];
    146 }; 147 } 148 else if (image) {
    151 completedBlock(image, nil, cacheType, YES, url);
    155 [self.runningOperations removeObject:operation];
    157 } 158 else { 159 // Image not in cache and download disallowed by delegate
    162 completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
    166 [self.runningOperations removeObject:operation];
    168 } 169 }]; 170 171 return operation; 172 }
    SDImageCache
    1
    - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock { 11 // First check the in-memory cache... 12 UIImage *image = [self imageFromMemoryCacheForKey:key]; 13 if (image) { 14 doneBlock(image, SDImageCacheTypeMemory); 15 return nil; 16 } 17 18 NSOperation *operation = [NSOperation new]; 19 dispatch_async(self.ioQueue, ^{ 20 if (operation.isCancelled) { 21 return; 22 } 23 24 @autoreleasepool { 25 UIImage *diskImage = [self diskImageForKey:key]; 26 if (diskImage) { 27 CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale; 28 [self.memCache setObject:diskImage forKey:key cost:cost]; 29 } 30 31 dispatch_async(dispatch_get_main_queue(), ^{ 32 doneBlock(diskImage, SDImageCacheTypeDisk); 33 }); 34 } 35 }); 36 37 return operation; 38 }
    SDWebImageDownloader
    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock {
        __block SDWebImageDownloaderOperation *operation;
        [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{
                timeoutInterval = 15.0;
            // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
            NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url 
                                             cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData)

                                          timeoutInterval:timeoutInterval]; operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) { SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey]; if (callback) callback(receivedSize, expectedSize); } completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey]; if (callback) callback(image, data, error, finished); } cancelled:^{ [sself removeCallbacksForURL:url]; }]; [wself.downloadQueue addOperation:operation]; [wself.lastAddedOperation addDependency:operation]; }]; return operation; }

    - (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock 
    andCompletedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
    forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback
    {
    dispatch_barrier_sync(self.barrierQueue, ^{
    BOOL first = NO;
    if (!self.URLCallbacks[url]) {
    self.URLCallbacks[url] = [NSMutableArray new];//第一次请求该url,新建URLCallbacks数组
    first = YES;//标示是第一次
    }

    // Handle single download of simultaneous download request for the same URL
    NSMutableArray *callbacksForURL = self.URLCallbacks[url];
    NSMutableDictionary *callbacks = [NSMutableDictionary new];
    if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];//保存progressBlock
    if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];//保存completedBlock
    [callbacksForURL addObject:callbacks];//
    保存至URLCallbacks
    self.URLCallbacks[url] = callbacksForURL;保存至self.URLCallbacks
    if (first) {
    createCallback();//第一次请求该url,执行createCallback
    }
    });
    }
     

     

  • 相关阅读:
    中序遍历【递归算法】和【非递归算法】
    等价无穷小替换
    轮转访问MAC协议
    曲率
    Java I/O流 01
    Java 集合框架 04
    Java 集合框架 03
    Java 集合框架 02
    Java 集合框架 01
    Java 常见对象 05
  • 原文地址:https://www.cnblogs.com/so-magic/p/4748729.html
Copyright © 2020-2023  润新知