SDWebImage - 图片实际下载代码

SDWebImage的图片下载代码主要集中在SDWebImageDownloader类与SDWebImageDownloaderOperation类中。后者是真正的将图片数据从网络上下载到终端的操作,前者主要是对后者进行并发处理。

SDWebImageDownloaderOperation

它是一个NSOperation的子类,并实现了SDWebImageOperation、NSURLSessionTaskDelegate、NSURLSessionDataDelegate等协议,定义如下:

@interface SDWebImageDownloaderOperation : NSOperation 

-(instanceType)initWithRequest:(NSURLRequest*)request 
                     inSession:(NSURLSession*)session 
                        options:(SDWebImageDownloaderOptions)options 
                        progress:(SDWebImageDownloaderProgressBlock)progressBlock 
                      completed:(SDWebImageDownloaderCompletedBlock)completedBlock 
                      cancelled:(SDWebImageNoParamsBlock)cancelBlock;

@end 

从初始化接口定义来看,该类会将下载过程中的回调Block保存起来并在后续的实际下载过程中触发。既然是NSOperation类的子类,那么来看下它的具体实现函数start,具体逻辑见下图:


SDWebImage - 图片实际下载代码_第1张图片
SDWebImageDownloaderOperation start主要逻辑

NSURLSessionDelegate

SDWebImageDownloaderOperation主要通过实现NSURLSessionDataDelegate与NSURLSessionTaskDelegate两个协议来实现下载过程监控。

-(void)URLSession:(NSURLSession*)session dataTask:(NSURLSessionDataTask*)dataTask didReceiveData:(NSData*)data 
{
  //向缓存中追加刚接收到的数据
  //SDWebImageDownloaderProgressiveDownload模式下根据当前接收到的图片数据绘制部分图片,调用completedBlock
  //调用progressBlock,用于显示图片下载进度信息
}

-(void)URLSession:(NSURLSession*)session dataTask:(NSURLSessionDataTask*)dataTask willCacheResponse:(NSCachedURLResponse*)proposeResponse completionHandler:(void(^)(NSCachedURLResponse* cachedResponse))completionHandler
{
  //根据初始化时传入request参数确定当前图片的缓存机制
}

-(void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error
{
  //发送SDWebImageDownloadStopNotification消息
  //error不为空,发送SDWebImageDownloadFinishNotification
  //调用completionBlock,将下载结束的具体信息传出
}

SDWebImageDownloader

该类中与图片下载有关的成员变量、成员函数如下:

@property (strong, nonatomic) NSOperationQueue* downloadQueue;
@property (strong, nonatomic) dispatch_queue_t barrierQueue;

-(id)downloadImageWithURL:(NSURL*)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock;

downloadImageWithURL:options:progress:completed

这个函数实际上很简单,不要被它里面的几个Block定义迷惑住了。它在内部只是调用了addProgressCallback:completedBlock:forURL:createCallback:接口,然后直接返回了。addProgressCallback函数内部将传入进来的各种callbackBlock组合成一个字典中,该字典通过图片URL地址保存在SDWebImageDownloader对象的URLCallbacks变量中。代码如下:

-(void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL*)url createCallback:(SDWebImageNoParamsBlock)createCallback
{
  if(url == nil){
    if(completedBlock != nil){
      completedBlock(nil, nil, nil, NO);
    }
    return;
  }
  
  dispatch_barrier_sync(self.barrierQueue, ^{
    BOOL first = NO;
    if(!self.URLCallbacks[url]){
      self.URLCallbacks[url] = [NSMutableArray new];
      first = YES;
     }
     NSMutableArray* callbacksForURL = self.URLCallbacks[url];
     NSMutableDictionary* callbacks = [NSMutableDictionary new];
     if(progressBlock){
       callbacks[kProgressCallbackKey] = [progressBlock copy]; 
     }
     if(completedBlock){
       callbacks[kCompletedCallbackKey] = [completedBlockcopy]; 
     }
     self.URLCallbacks[url] = callbacksForURL;
     if(first){
        createCallback();
     }
  });
}

从上面代码中我们可以看到,downloadImageWithURL中传入的progressBlock与completedBlock都被缓存起来了,而createCallback则是在当前下载地址末在下载队列中时调用,主要功能就是创建SDWebImageDownloadOperation对象并添加到下载队列中。

再回到downloadImageWithURL的具体实现中,可以看到SDWebImageDownloadOperation对象创建过程中,progressBlock与completedBlock基本逻辑是从成员变量URLCallbacks中获取玩家传入的Block后调用,而completedBlock另外多的一步是判断是否将同图片URL标识的callback组合数组从URLCallbacks中删除。

你可能感兴趣的:(SDWebImage - 图片实际下载代码)