SDWebImage的一些理解

SDWebImage的使用

SDWebImage的一些理解_第1张图片
SDWebImageView.png
  • 按钮:
    [imageBtn sd_setImageWithURL:url forState:UIControlStateNormal placeholderImage:[UIImage imageNamed:@"chatListCellHead"]]

  • imageView:
    [imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"chatListCellHead"]];

SDWebImage的实现

上面两个方法最终由- (id )downloadImageWithURL:(NSURL *)url
                                     options:(SDWebImageOptions)options
                                    progress:(SDWebImageDownloaderProgressBlock)progressBlock
                                   completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {}
 这个方法实现
  • SDWebImageManager
    这个类有两个队列
    @property (strong, nonatomic) NSMutableSet *failedURLs;//下载失败的URL名单
    @property (strong, nonatomic) NSMutableArray *runningOperations;//下载队列

    @property (strong, nonatomic, readwrite) SDImageCache *imageCache;//图片缓存
    @property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;//下载器
    
  • 先判断url
    if ([url isKindOfClass:NSString.class]) {
    url = [NSURL URLWithString:(NSString *)url];
    }
    if (![url isKindOfClass:NSURL.class]) {
    url = nil;
    }

  • 新建一个新的操作
    __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];//新生成一个操作
    __weak SDWebImageCombinedOperation *weakOperation = operation;

  • 判断是否是下载失败的url
    BOOL isFailedUrl = NO;
    @synchronized (self.failedURLs) {
    isFailedUrl = [self.failedURLs containsObject:url];
    }
    //url为nil或者 URL下载失败且设置了失败不再重试
    if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
    //失败处理
    dispatch_main_sync_safe(^{
    NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
    completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
    });
    return operation;
    }

  • 加入队列 取消之前图片的下载
    @synchronized (self.runningOperations) {
    //添加到下载队列
    [self.runningOperations addObject:operation];
    }
    NSString *key = [self cacheKeyForURL:url];//根据URL生成key

    operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
      //operation取消,那么将下载任务从下载队列直接移除
      if (operation.isCancelled) {
          @synchronized (self.runningOperations) {
              [self.runningOperations removeObject:operation];
          }
          return;
      }
    
  • 下载
    if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
    if (image && options & SDWebImageRefreshCached) {
    dispatch_main_sync_safe(^{
    // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image
    // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
    completedBlock(image, nil, cacheType, YES, url);
    });
    }

          // download if no image or requested to refresh anyway, and download allowed by delegate
          // 下载图片
          SDWebImageDownloaderOptions downloaderOptions = 0;
          if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
          if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
          if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
          if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
          if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
          if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
          if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
          if (image && options & SDWebImageRefreshCached) {
              // force progressive off if image already cached but forced refreshing
              downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
              // ignore image read from NSURLCache if image if cached but force refreshing
              downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
          }
          //下载操作
          id  subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
              __strong __typeof(weakOperation) strongOperation = weakOperation;
              if (!strongOperation || strongOperation.isCancelled) {
                  // Do nothing if the operation was cancelled
                  // See #699 for more details
                  // 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
              }
              else if (error) {
                  //错误处理
                  dispatch_main_sync_safe(^{
                      if (strongOperation && !strongOperation.isCancelled) {
                          completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
                      }
                  });
    
                  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];
                      }
                  }
              }
              else {
                  if ((options & SDWebImageRetryFailed)) {
                      @synchronized (self.failedURLs) {
                          [self.failedURLs removeObject:url];
                      }
                  }
                  
                  BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
    
                  if (options & SDWebImageRefreshCached && image && !downloadedImage) {
                      // Image refresh hit the NSURLCache cache, do not call the completion block
                  }
                  else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
                      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                          //图片转换
                          UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
                          if (transformedImage && finished) {
                              BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];//图片是否转化
                              //保存图片到缓存
                              [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];
                          }
    
                          dispatch_main_sync_safe(^{
                              if (strongOperation && !strongOperation.isCancelled) {
                                  completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
                              }
                          });
                      });
                  }
                  else {
                       //保存图片到缓存,调用下载完成Block
                      if (downloadedImage && finished) {
                          [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
                      }
    
                      dispatch_main_sync_safe(^{
                          if (strongOperation && !strongOperation.isCancelled) {
                              completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
                          }
                      });
                  }
              }
    
              if (finished) {
                  //从运行的下载队列移除下载操作
                  @synchronized (self.runningOperations) {
                      if (strongOperation) {
                          [self.runningOperations removeObject:strongOperation];
                      }
                  }
              }
          }];
          //取消操作的Block
          operation.cancelBlock = ^{
              [subOperation cancel];
              
              @synchronized (self.runningOperations) {
                  __strong __typeof(weakOperation) strongOperation = weakOperation;
                  if (strongOperation) {
                      [self.runningOperations removeObject:strongOperation];
                  }
              }
          };
      }
      else if (image) {
          dispatch_main_sync_safe(^{
              //下载成功 从运行的下载队列移除下载操作
              __strong __typeof(weakOperation) strongOperation = weakOperation;
              if (strongOperation && !strongOperation.isCancelled) {
                  completedBlock(image, nil, cacheType, YES, url);
              }
          });
          @synchronized (self.runningOperations) {
              [self.runningOperations removeObject:operation];
          }
      }
      else {
          // Image not in cache and download disallowed by delegate
          dispatch_main_sync_safe(^{
              __strong __typeof(weakOperation) strongOperation = weakOperation;
              if (strongOperation && !weakOperation.isCancelled) {
                  completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
              }
          });
          @synchronized (self.runningOperations) {
              [self.runningOperations removeObject:operation];
          }
      }
    

你可能感兴趣的:(SDWebImage的一些理解)