Authored by Harish Krishnamurthy
Committed by Bogdan Poplauschi

Modifies SDWebImagePrefetcher prefetching logic.

- Removes recursive calls to startPrefetchingAtIndex.
- Uses dispatch_apply with striding to optimize the performance.
@@ -78,12 +78,7 @@ @@ -78,12 +78,7 @@
78 didPrefetchURL:self.prefetchURLs[index] 78 didPrefetchURL:self.prefetchURLs[index]
79 finishedCount:self.finishedCount 79 finishedCount:self.finishedCount
80 totalCount:self.prefetchURLs.count 80 totalCount:self.prefetchURLs.count
81 - ];  
82 - }  
83 - if (self.prefetchURLs.count > self.requestedCount) {  
84 - dispatch_async(self.prefetcherQueue, ^{  
85 - [self startPrefetchingAtIndex:self.requestedCount];  
86 - }); 81 + ];
87 } 82 }
88 else if (self.finishedCount == self.requestedCount) { 83 else if (self.finishedCount == self.requestedCount) {
89 [self reportStatus]; 84 [self reportStatus];
@@ -102,7 +97,7 @@ @@ -102,7 +97,7 @@
102 [self.delegate imagePrefetcher:self 97 [self.delegate imagePrefetcher:self
103 didFinishWithTotalCount:(total - self.skippedCount) 98 didFinishWithTotalCount:(total - self.skippedCount)
104 skippedCount:self.skippedCount 99 skippedCount:self.skippedCount
105 - ]; 100 + ];
106 } 101 }
107 } 102 }
108 103
@@ -117,14 +112,29 @@ @@ -117,14 +112,29 @@
117 self.completionBlock = completionBlock; 112 self.completionBlock = completionBlock;
118 self.progressBlock = progressBlock; 113 self.progressBlock = progressBlock;
119 114
120 - if(urls.count == 0){ 115 + __weak SDWebImagePrefetcher *weakSelf = self;
  116 +
  117 + if(urls.count == 0){
121 if(completionBlock){ 118 if(completionBlock){
122 completionBlock(0,0); 119 completionBlock(0,0);
123 } 120 }
124 }else{ 121 }else{
125 - // Starts prefetching from the very first image on the list with the max allowed concurrency  
126 - NSUInteger listCount = self.prefetchURLs.count;  
127 - for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { 122 + // http://oleb.net/blog/2013/07/parallelize-for-loops-gcd-dispatch_apply/
  123 + // Optimize the maxConcurrentdownloads for effeciency. Since caching operations are involved that are non-trivial using
  124 + // dispatch_apply might be helpful.
  125 +
  126 + NSInteger maxNumberOfImages = self.prefetchURLs.count;
  127 +
  128 + dispatch_apply(maxNumberOfImages/self.maxConcurrentDownloads, dispatch_get_global_queue(self.prefetcherQueue, 0), ^(size_t index) {
  129 + size_t i = index * self.maxConcurrentDownloads;
  130 + size_t stop = i + self.maxConcurrentDownloads;
  131 + do{
  132 + [weakSelf startPrefetchingAtIndex:i++];
  133 + }while (i < stop);
  134 + });
  135 +
  136 + // Download remaining images.
  137 + for (size_t i = maxNumberOfImages - (maxNumberOfImages % self.maxConcurrentDownloads); i < (size_t)maxNumberOfImages; i++) {
128 [self startPrefetchingAtIndex:i]; 138 [self startPrefetchingAtIndex:i];
129 } 139 }
130 } 140 }