diff --git a/SDWebImagePrefetcher.h b/SDWebImagePrefetcher.h new file mode 100644 index 00000000..bab599ba --- /dev/null +++ b/SDWebImagePrefetcher.h @@ -0,0 +1,44 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageManagerDelegate.h" + +@interface SDWebImagePrefetcher : NSObject +{ + 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 diff --git a/SDWebImagePrefetcher.m b/SDWebImagePrefetcher.m new file mode 100644 index 00000000..7dbf35c3 --- /dev/null +++ b/SDWebImagePrefetcher.m @@ -0,0 +1,112 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * 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