Permalink
Browse files

Add SDWebImagePrefetcher, an utility class to preventively warm-up SD…

…WebImage cache (fix #32)

Contributed by https://github.com/mystcolor
  • Loading branch information...
1 parent 9e2d414 commit 23ae1cb00c662c685de4a9016b7bd079a9a5f19b @rs rs committed Oct 4, 2011
Showing with 156 additions and 0 deletions.
  1. +44 −0 SDWebImagePrefetcher.h
  2. +112 −0 SDWebImagePrefetcher.m
View
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the SDWebImage package.
+ * (c) Olivier Poitrey <rs@dailymotion.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#import <Foundation/Foundation.h>
+#import "SDWebImageManagerDelegate.h"
+
+@interface SDWebImagePrefetcher : NSObject <SDWebImageManagerDelegate>
+{
+ NSArray *_prefetchURLs;
+ NSUInteger _skippedCount;
+ NSUInteger _finishedCount;
+ NSUInteger _requestedCount;
+ NSTimeInterval _startedTime;
+}
+
+/**
+ * Maximum number of URLs to prefetch at the same time. Defaults to 3.
+ */
+@property (nonatomic, assign) NSUInteger maxConcurrentDownloads;
+
++ (SDWebImagePrefetcher *)sharedImagePrefetcher;
+
+/**
+ * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching,
+ * currently one image is downloaded at a time,
+ * and skips images for failed downloads and proceed to the next image in the list
+ *
+ * @param NSArray list of URLs to prefetch
+ */
+- (void)prefetchURLs:(NSArray *)urls;
+
+
+/**
+ * Remove and cancel queued list
+ */
+- (void)cancelPrefetching;
+
+
+@end
View
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the SDWebImage package.
+ * (c) Olivier Poitrey <rs@dailymotion.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#import "SDWebImagePrefetcher.h"
+#import "SDWebImageManager.h"
+
+@interface SDWebImagePrefetcher ()
+@property (nonatomic, retain) NSArray *prefetchURLs;
+@end
+
+@implementation SDWebImagePrefetcher
+
+static SDWebImagePrefetcher *instance;
+
+@synthesize prefetchURLs;
+@synthesize maxConcurrentDownloads;
+
++ (SDWebImagePrefetcher *)sharedImagePrefetcher
+{
+ if (instance == nil)
+ {
+ instance = [[SDWebImagePrefetcher alloc] init];
+ instance.maxConcurrentDownloads = 3;
+ }
+
+ return instance;
+}
+
+- (void)startPrefetchingAtIndex:(NSUInteger)index withManager:(SDWebImageManager *)imageManager
+{
+ if (index >= [self.prefetchURLs count]) return;
+ _requestedCount++;
+ [imageManager downloadWithURL:[self.prefetchURLs objectAtIndex:index] delegate:self options:SDWebImageLowPriority];
+}
+
+- (void)reportStatus
+{
+ NSUInteger total = [self.prefetchURLs count];
+ NSLog(@"Finished prefetching (%d successful, %d skipped, timeElasped %.2f)", total - _skippedCount, _skippedCount, CFAbsoluteTimeGetCurrent() - _startedTime);
+}
+
+- (void)prefetchURLs:(NSArray *)urls
+{
+ [self cancelPrefetching]; // Prevent duplicate prefetch request
+ _startedTime = CFAbsoluteTimeGetCurrent();
+ self.prefetchURLs = urls;
+
+ // Starts prefetching from the very first image on the list with the max allowed concurrency
+ int listCount = [self.prefetchURLs count];
+ SDWebImageManager *manager = [SDWebImageManager sharedManager];
+ for (int i = 0; i < self.maxConcurrentDownloads && _requestedCount < listCount; i++)
+ {
+ [self startPrefetchingAtIndex:i withManager:manager];
+ }
+}
+
+- (void)cancelPrefetching
+{
+ self.prefetchURLs = nil;
+ _skippedCount = 0;
+ _requestedCount = 0;
+ _finishedCount = 0;
+ [[SDWebImageManager sharedManager] cancelForDelegate:self];
+}
+
+#pragma mark SDWebImagePrefetcher (SDWebImageManagerDelegate)
+
+- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image
+{
+ _finishedCount++;
+ NSLog(@"Prefetched %d out of %d", _finishedCount, [self.prefetchURLs count]);
+
+ if ([self.prefetchURLs count] > _requestedCount)
+ {
+ [self startPrefetchingAtIndex:_requestedCount withManager:imageManager];
+ }
+ else if (_finishedCount == _requestedCount)
+ {
+ [self reportStatus];
+ }
+}
+
+- (void)webImageManager:(SDWebImageManager *)imageManager didFailWithError:(NSError *)error
+{
+ _finishedCount++;
+ NSLog(@"Prefetched %d out of %d (Failed)", _finishedCount, [self.prefetchURLs count]);
+
+ // Add last failed
+ _skippedCount++;
+
+ if ([self.prefetchURLs count] > _requestedCount)
+ {
+ [self startPrefetchingAtIndex:_requestedCount withManager:imageManager];
+ }
+ else if (_finishedCount == _requestedCount)
+ {
+ [self reportStatus];
+ }
+}
+
+- (void)dealloc
+{
+ self.prefetchURLs = nil;
+ [super dealloc];
+}
+
+@end

0 comments on commit 23ae1cb

Please sign in to comment.