美文网首页
源码解读-SDWebImage3.8.2

源码解读-SDWebImage3.8.2

作者: Harry_Coding | 来源:发表于2019-03-06 16:59 被阅读0次
    • 架构


    • 底层处理类:
      SDImageCache(负责image的存储)
      SDWebImageDownloader (负责webImage的下载)
      SDWebImageDownloaderOperation (继承自NSOpration的下载任务类)
    • 工具辅助类
      NSData+ImageContentType(负责根据图片Data获取图片类型)
      SDWebImageCompat(定义根据url后2x,3x处理图片scale(缩放因子)、以及定义安全主队列执行宏)
      UIImage+MultiFormat(根据Data区分类型获取正确的图片)
      UIImage+GIF(处理GIF图片分类)
      UIView+WebCacheOperation(用于存储在View类的operation或者取消operation)
    • 底层之上的处理类
      SDWebImageManager (负责采用SDWebImageDownloader和SDImageCache储存的逻辑整合管理类)
      SDWebImagePrefetcher (封装SDWebImageManager的SDWebImageManager预取器)
      UIButton+WebCache (UIButton设置网络图片的分类)
      UIImageView+HighlightedWebCache (UIImageView设置高亮webImage的分类)
      UIImageView+WebCache(UIImageView 设置webImage的分类)
    • 代码解读


    • SDImageCache

    负责图片存储、清理功能,主要分为memoryCache(内存缓存)和diskCache(磁盘缓存)。

    故定义存储类型为SDImageCacheType:SDImageCacheTypeNone、SDImageCacheTypeDisk、SDImageCacheTypeMemory。

    基本的属性就不在此做篇幅了,解释都很清楚。我们主要记录相关知识点以及设计思路。

    此类有意设计为一个单利类。同时也预留出了其他非单利初始化方法,方便用户自己定义一个存储区。通过sharedImageCache生成的是我们全局单利类,采用默认的存储路径;通过- (id)initWithNamespace:(NSString *)ns;- (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory;两个方法创建自己的存储路径。
    下面我们说一下,存、取以及清理。
    存的方式我们采用NSCache作为内存读写,采用NSFileManager作为磁盘读写。
    关于写:
    根据属性是否写入内存:如果写入内存,先[self.memCache setObject:image forKey:key cost:cost];设置NSCache,之后diskCache,diskCache采用GCD异步串行队列存储,异步保证不会阻塞当前线程,串行保证队列所有任务都能保证按FIFO的顺序执行,避免造成线程并发存储造成崩溃。从缓存中取图片的时候,首先会从NSCache中查找,再从DiskCache中查找。
    清理缓存:
    1. 按照key清理,清除内存缓存(根据shouldCacheImagesInMemory熟悉)->清除disk缓存(异步串行队列执行)
    2.全部清除:
    全部清除clear
    clearMemory([self.memCache removeAllObjects];)、clearDisk(异步串行队列删除缓存地址所有文件->创建缓存路径)
    清理clean
    清理缓存只有清理disk缓存,先清理过期的图片->按最后修改日期排序直到删除到缓存<最大缓存量(也就是算法中经常说的最近最少使用LRU算法)

    • SDWebImageDownloader

    此类也设计为单利,负责从网络上下载图片。网络请求采用NSURLSession处理(当然以前的NSURLConnection已经废弃了)

    关于下载流程主要浓缩于一个方法:- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock 在这个方法里调用了一个重要的方法- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback
    这个方法 应用dispatch_barrier_sync(GCD同步栅栏函数并发队列执行任务, 此函数的意义在于同步执行,并且当前任务直到在此之前加进去的所有任务执行完毕才会执行)执行从URLCallbacks取以url为键名的Array(存储了kProgressCallbackKey(进度回调)、kCompletedCallbackKey(完成回调))如果不存在,将其标记为first(第一次下载)并且初始化url对应的数组,然后将添保存进度和完成回调的字典添加进数组。如果第一次下载回调creatCallBack()。接下来我们看creatCallBack回调里做了什么事情:生成NSMutableURLRequest(配置相关属性)->生成SDWebImageDownloaderOperation(继承抽象类NSOperation的自定义类->配置operation的相关属性 -> 添加到自定义并发队列([NSOperationQueue addOperation] 添加完就会调用[NSOperation start])->如果执行顺序是SDWebImageDownloaderLIFOExecutionOrder,添加这次上次op依赖于这次op。那么SDWebImageDownloaderOperation又做了什么呢?
    它是继承自NSOperation抽象类的,并且实现了NSURLSessionTaskDelegate、NSURLSessionDataDelegate、SDWebImageOperation(自定义Operation协议)

    • (void)start
      通过可选项SDWebImageDownloaderOptions是否为SDWebImageDownloaderContinueInBackground后台继续下载模式,开启后台激活后台长运行任务[app beginBackgroundTaskWithExpirationHandler:^{}],用已经传进来的session继续执行任务。其中使用同步锁@synchronized (self){}执行属性赋值等操作
    • NSURLSessionDataDelegate
      - (void)URLSession:(NSURLSession *)session
      dataTask:(NSURLSessionDataTask *)dataTask
      didReceiveResponse:(NSURLResponse *)response
      completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler; // 开始接收到response的代理。如果返回statusCode < 400 && statusCode != 304说明返回数据正常,否则说明返回错误。正确赋值给预期大小,初始化imageData数据,回调进度block,通知SDWebImageDownloadReceiveResponseNotification;错误情况下取消任务发送SDWebImageDownloadStopNotification通知,回调完成block返回错误信息。
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data;// 开始接收数据代理,拼接接收到的数据,并且根据是否SDWebImageDownloaderProgressiveDownload,是否处理渐进下载。首先如果高度+宽度=0。获取宽度、高度、方向。CGImageSourceCreateWithData()创建CGImageSourceRef,获取CGImageSourceRef的info信息CFDictionaryRef,其中包括高度val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight)、宽度CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth)、以及方向CFDictionaryGetValue(properties, kCGImagePropertyOrientation)。

    如果当前width+height>0&& 当前数据大小<预期数据大小,根据当前数据生成图片 CGImageSourceCreateImageAtIndex生成CGImageRef, CGBitmapContextCreate()生成位图context,CGContextDrawImage()绘制到当前的位图context中,从当前的context中生成图片CGBitmapContextCreateImage(),根据imageRef生成image。
    - (void)URLSession:(NSURLSession *)session
    dataTask:(NSURLSessionDataTask *)dataTask
    willCacheResponse:(NSCachedURLResponse *)proposedResponse
    completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler;//将会缓存response,根据是否NSURLRequestReloadIgnoringLocalCacheData;阻止缓存
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;// 下载完成;首先清空数据发送下载完毕通知或者停止通知, 其次根据是否error,分别赋值不同的完成回调参数。主要看!error的情况:1.如果response从缓存里取得,那么返回nil的image;2.如果imageData存在通过分类方法sd_imageWithData生成图片2.1如果尺寸为0那么回调参数赋值错误原因2.2否则返回正确回调3.返回无数据错误完成回调
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;// 处理相关认证

    • SDWebImageManager

    此类也设计为单利,同时也提供了自定义downloader、cache初始化。其中单利默认采用SDWebImageDownloader下载图片SDImageCache存取图片。

    主要类解析:
    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
    options:(SDWebImageOptions)options
    progress:(SDWebImageDownloaderProgressBlock)progressBlock
    completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;

    1. 转化url参数为NSURL
      2.判断(url是否在失败池&&operations不包括包括SDWebImageRetryFailed)|| url有错,直接返回错误结束任务。
      3.将创建好的operation加入到runningOperations
    2. 用[SDImageCache queryDiskCacheForKey]查找缓存图片,回调处理
      4.1任务取消,结束
      4.2 ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) 处理
      4.2.1如果图片存在并且operations包括SDWebImageRefreshCached,先回调完成block返回数据;再组合operations 利用SDImageDownloader下载图片,回调处理
      4.2.1.1 operation取消,不做任何操作
      4.2.1.2 下载错误,将此URL添加到失败池,返回完成回调但会错误。
      4.2.1.3 除此只玩的相关处理:1.options & SDWebImageRetryFailed 移除失败池的当前url2.options & SDWebImageRefreshCached && image && !downloadedImage 未做操作3.(downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:) DownloadImage存在&&(downloadimage没有不是GIF||做过处理)
      从代理中获取处理过的图片,如果图片存在并且下载完全完成,储存图片,回调完成block。
      4.2.1.4 下载图片存在&&下载已经完成 缓存图片 回调完成block
      4.2.1.4 全部完成下载,移除执行操作池当前操作
      4.2.2 如果image存在 回调完成block,移除执行操作池当前操作
      4.2.3否则回调block,SDImageCacheTypeNone
    • SDWebImagePrefetcher

    利用SDWebImageManager 进行预下载多个图片

    • UIImageView+WebCache

    快速设置网络图片的UIImageView分类。

    我们只需要看,他的“全能初始化方法”
    - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock

    1.取消当前所有获取image任务
    2.根据是都延迟赋值placeholder赋值
    3.[SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) 查询或者下载图片
    4.回调中根据选项处理图片。
    从底层看到这里其实这部分的代码就so easy了,就不细说了。

    关于其他工具类,和分类就不一一记录了。

    相关文章

      网友评论

          本文标题:源码解读-SDWebImage3.8.2

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