源码阅读:SDWebImage(十五)——SDWebImagePrefetcher

该文章阅读的SDWebImage的版本为4.3.3。

该类是SDWebImageManager类的一个应用——预加载:以较低优先级批量下载图像进行缓存,以供未来使用。

1.SDWebImagePrefetcherDelegate协议

/**
 当一张图片已经预加载好的时候会调用这个方法
 */
- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
复制代码
/**
 当所有图片都已经预加载好的时候会调用这个方法
 */
- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
复制代码

2.公共类型定义

/**
 定义用于回调进度情况的block
 */
typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls);
复制代码
/**
 定义用于回调完成情况的block
 */
typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls);
复制代码

3.公共属性

/**
 网络图像管理者对象
 */
@property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager;
复制代码
/**
 最大图像预加载数量,默认为3张
 */
@property (nonatomic, assign) NSUInteger maxConcurrentDownloads;
复制代码
/**
 图像加载选项,默认为SDWebImageLowPriority,也就是低优先级
 */
@property (nonatomic, assign) SDWebImageOptions options;
复制代码
/**
 预加载所在的队列,默认是主队列
 */
@property (strong, nonatomic, nonnull) dispatch_queue_t prefetcherQueue;
复制代码
/**
 代理对象
 */
@property (weak, nonatomic, nullable) id <SDWebImagePrefetcherDelegate> delegate;
复制代码

4.公共方法

/**
 获取单例对象
 */
+ (nonnull instancetype)sharedImagePrefetcher;
复制代码
/**
 以指定的网络图像管理者对象进行初始化
 */
- (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER;
复制代码
/**
 预加载的图像url数组
 */
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls;
复制代码
/**
 预加载的图像url数组,并回调进度和完成情况
 */
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls
            progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
           completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock;
复制代码
/**
 取消所有预加载任务
 */
- (void)cancelPrefetching;
复制代码

5.类扩展属性

/**
 保存网络图像管理者对象
 */
@property (strong, nonatomic, nonnull) SDWebImageManager *manager;
复制代码
/**
 保存预加载的图像url数组
 */
@property (strong, atomic, nullable) NSArray<NSURL *> *prefetchURLs; 
复制代码
/**
 保存请求的数量
 */
@property (assign, nonatomic) NSUInteger requestedCount;
复制代码
/**
 保存跳过的数量
 */
@property (assign, nonatomic) NSUInteger skippedCount;
复制代码
/**
 保存完成的数量
 */
@property (assign, nonatomic) NSUInteger finishedCount;
复制代码
/**
 保存预加载开始的时间
 */
@property (assign, nonatomic) NSTimeInterval startedTime;
复制代码
/**
 保存完成回调block
 */
@property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock;
复制代码
/**
 保存进程回调block
 */
@property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock;
复制代码

6.方法实现

6.1.生命周期方法实现

- (nonnull instancetype)init {
    // 创建新的网络图像管理者对象初始化
    return [self initWithImageManager:[SDWebImageManager new]];
}
复制代码

6.2.私有方法实现

/**
 开始预加载指定索引的图像
 */
- (void)startPrefetchingAtIndex:(NSUInteger)index {
    // 创建变量保存当前正在预加载的url
    NSURL *currentURL;
    // 加锁
    @synchronized(self) {
        // 如果想要预加载的索引超过了总共要预加载的数量,就返回不继续向下执行了
        if (index >= self.prefetchURLs.count) return;
        // 记录要预加载的url
        currentURL = self.prefetchURLs[index];
        // 记录请求数量
        self.requestedCount++;
    }
    // 调用网络图像管理者对象加载图像
    [self.manager loadImageWithURL:currentURL options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
        // 如果没有完成就返回
        if (!finished) return;
        // 记录完成数量
        self.finishedCount++;

        // 如果设置了进度回调block就回调进度情况
        if (self.progressBlock) {
            self.progressBlock(self.finishedCount,(self.prefetchURLs).count);
        }
        // 如果图像没有加载成功就记录跳过数量
        if (!image) {
            self.skippedCount++;
        }
        // 如果代理对象实现了代理方法,就调用传递完成情况
        if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) {
            [self.delegate imagePrefetcher:self
                            didPrefetchURL:currentURL
                             finishedCount:self.finishedCount
                                totalCount:self.prefetchURLs.count
             ];
        }
        if (self.prefetchURLs.count > self.requestedCount) {
            // 如果总共要预加载的数量比请求的数量多
            // 主队列异步加载
            dispatch_async(self.prefetcherQueue, ^{
                // 开始预加载下一个图像
                [self startPrefetchingAtIndex:self.requestedCount];
            });
        } else if (self.finishedCount == self.requestedCount) {
            // 如果完成的数量等于请求的数量
            // 回调状态
            [self reportStatus];
            // 如果设置了完成回调block就回调完成情况
            if (self.completionBlock) {
                self.completionBlock(self.finishedCount, self.skippedCount);
                // 置空保存完成回调block的属性
                self.completionBlock = nil;
            }
            // 置空保存进度回调block的属性
            self.progressBlock = nil;
        }
    }];
}
复制代码
/**
 回调状态
 */
- (void)reportStatus {
    // 获取总共要预加载的数量
    NSUInteger total = (self.prefetchURLs).count;
    // 如果代理对象实现了代理方法,就调用传递完成情况
    if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) {
        [self.delegate imagePrefetcher:self
               didFinishWithTotalCount:(total - self.skippedCount)
                          skippedCount:self.skippedCount
         ];
    }
}
复制代码

6.3.公共方法实现

+ (nonnull instancetype)sharedImagePrefetcher {
    // 获取单例对象
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [self new];
    });
    return instance;
}
复制代码
- (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager {
    if ((self = [super init])) {
        // 保存网络图像管理者对象
        _manager = manager;
        // 默认为低优先级
        _options = SDWebImageLowPriority;
        // 预加载队列为主队列
        _prefetcherQueue = dispatch_get_main_queue();
        // 最大预加载并发数为3
        self.maxConcurrentDownloads = 3;
    }
    return self;
}
复制代码
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls {
    // 调用下面的全能方法
    [self prefetchURLs:urls progress:nil completed:nil];
}
复制代码
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls
            progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
           completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock {
    // 取消之前的预加载操作
    [self cancelPrefetching]; 
    // 获取当前时间
    self.startedTime = CFAbsoluteTimeGetCurrent();
    // 获取要预加载的url
    self.prefetchURLs = urls;
    // 保存完成回调block
    self.completionBlock = completionBlock;
    // 保存进度回调block
    self.progressBlock = progressBlock;

    if (urls.count == 0) {
        // 如果没有要预加载的url就直接回调
        if (completionBlock) {
            completionBlock(0,0);
        }
    } else {
        // 开启预加载
        NSUInteger listCount = self.prefetchURLs.count;
        for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) {
            [self startPrefetchingAtIndex:i];
        }
    }
}
复制代码
- (void)cancelPrefetching {
    // 加锁
    @synchronized(self) {
        // 置空保存要预加载的url数组的属性
        self.prefetchURLs = nil;
        // 置空保存跳过数量的属性
        self.skippedCount = 0;
        // 置空保存请求数量的属性
        self.requestedCount = 0;
        // 置空保存完成数量的属性
        self.finishedCount = 0;
    }
    // 调用网络图像管理者对象取消所有操作
    [self.manager cancelAll];
}
复制代码

6.4.自定义getter/setter方法实现

- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads {
    // 直接设置网络图像管理者对象的最大并发数
    self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads;
}
复制代码
- (NSUInteger)maxConcurrentDownloads {
    // 直接获取网络图像管理者对象的最大并发数
    return self.manager.imageDownloader.maxConcurrentDownloads;
}
复制代码

7.总结

这个类利用前面对图像加载功能的良好封装,非常简洁的实现了预加载图像的功能。

源码阅读系列:SDWebImage

源码阅读:SDWebImage(一)——从使用入手

源码阅读:SDWebImage(二)——SDWebImageCompat

源码阅读:SDWebImage(三)——NSData+ImageContentType

源码阅读:SDWebImage(四)——SDWebImageCoder

源码阅读:SDWebImage(五)——SDWebImageFrame

源码阅读:SDWebImage(六)——SDWebImageCoderHelper

源码阅读:SDWebImage(七)——SDWebImageImageIOCoder

源码阅读:SDWebImage(八)——SDWebImageGIFCoder

源码阅读:SDWebImage(九)——SDWebImageCodersManager

源码阅读:SDWebImage(十)——SDImageCacheConfig

源码阅读:SDWebImage(十一)——SDImageCache

源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation

源码阅读:SDWebImage(十三)——SDWebImageDownloader

源码阅读:SDWebImage(十四)——SDWebImageManager

源码阅读:SDWebImage(十五)——SDWebImagePrefetcher

源码阅读:SDWebImage(十六)——SDWebImageTransition

源码阅读:SDWebImage(十七)——UIView+WebCacheOperation

源码阅读:SDWebImage(十八)——UIView+WebCache

源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

源码阅读:SDWebImage(二十)——UIButton+WebCache

源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值