Authored by 朱小军

sdwebimage下载时获取ip在子线程进行,避免下载图片卡顿问题 review by christ

@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 static NSString *const kProgressCallbackKey = @"progress"; 15 static NSString *const kProgressCallbackKey = @"progress";
16 static NSString *const kCompletedCallbackKey = @"completed"; 16 static NSString *const kCompletedCallbackKey = @"completed";
17 17
18 -@interface SDWebImageDownloader ()<HttpDNSDegradationDelegate> 18 +@interface SDWebImageDownloader ()
19 19
20 @property (strong, nonatomic) NSOperationQueue *downloadQueue; 20 @property (strong, nonatomic) NSOperationQueue *downloadQueue;
21 @property (weak, nonatomic) NSOperation *lastAddedOperation; 21 @property (weak, nonatomic) NSOperation *lastAddedOperation;
@@ -25,26 +25,12 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -25,26 +25,12 @@ static NSString *const kCompletedCallbackKey = @"completed";
25 // This queue is used to serialize the handling of the network responses of all the download operation in a single queue 25 // This queue is used to serialize the handling of the network responses of all the download operation in a single queue
26 @property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t barrierQueue; 26 @property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t barrierQueue;
27 27
28 -@property (copy, nonatomic) NSString *dnsFlag; 28 +@property (assign, nonatomic) BOOL enableHttpDNS;
29 29
30 @end 30 @end
31 31
32 @implementation SDWebImageDownloader 32 @implementation SDWebImageDownloader
33 33
34 -- (BOOL)shouldDegradeHTTPDNS:(NSString *)hostName  
35 -{  
36 -#ifdef M0  
37 - return YES;  
38 -#else  
39 -  
40 - if ([self.dnsFlag isEqualToString:@"2a90dfa0f37b92aaebf369e9a4d38ba4"]) {  
41 - return NO;  
42 - }  
43 -  
44 - return YES;  
45 -#endif  
46 -}  
47 -  
48 + (void)initialize { 34 + (void)initialize {
49 // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator ) 35 // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
50 // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import 36 // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
@@ -93,13 +79,10 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -93,13 +79,10 @@ static NSString *const kCompletedCallbackKey = @"completed";
93 _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT); 79 _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
94 _downloadTimeout = 15.0; 80 _downloadTimeout = 15.0;
95 81
96 - _dnsFlag = [[NSUserDefaults standardUserDefaults] stringForKey:@"kUserConfigHttpDNS"];  
97 -  
98 - [[HttpDnsService sharedInstance] setAccountID:160270];  
99 - [[HttpDnsService sharedInstance] setDelegateForDegradationFilter:(id<HttpDNSDegradationDelegate>)self];  
100 - [[HttpDnsService sharedInstance] setExpiredIPEnabled:YES];  
101 #if DEBUG 82 #if DEBUG
102 - [[HttpDnsService sharedInstance] setLogEnabled:YES]; 83 + _enableHttpDNS = YES;
  84 +#else
  85 + _enableHttpDNS = [[[NSUserDefaults standardUserDefaults] stringForKey:@"kUserConfigHttpDNS"] isEqualToString:@"2a90dfa0f37b92aaebf369e9a4d38ba4"];
103 #endif 86 #endif
104 } 87 }
105 return self; 88 return self;
@@ -142,99 +125,100 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -142,99 +125,100 @@ static NSString *const kCompletedCallbackKey = @"completed";
142 - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { 125 - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock {
143 __block SDWebImageDownloaderOperation *operation; 126 __block SDWebImageDownloaderOperation *operation;
144 __weak __typeof(self)wself = self; 127 __weak __typeof(self)wself = self;
145 -  
146 - BOOL useAliDNS = NO;  
147 - NSString *imageURLHost = url.host;//获取图片URL的host  
148 - NSURL *newURL = url;  
149 - if (imageURLHost.length > 0) {  
150 - NSArray *ips = [[HttpDnsService sharedInstance] getIpsByHost:imageURLHost];//同步请求ip地址列表  
151 - if ([ips isKindOfClass:[NSArray class]] && [ips respondsToSelector:@selector(count)] && ips.count > 0) {  
152 - NSString *ipAdress = [ips objectAtIndex:0];  
153 - NSString *urlString = [url absoluteString];  
154 - NSRange hostRange = [urlString rangeOfString:imageURLHost];  
155 - if (NSNotFound != hostRange.location) {  
156 - useAliDNS = YES;  
157 - NSString *convertedURLString = [urlString stringByReplacingCharactersInRange:hostRange withString:ipAdress];//host转换之后的urlstring  
158 - newURL = [NSURL URLWithString:convertedURLString]; //替换原始url为转换后的值 128 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  129 + BOOL useAliDNS = NO;
  130 + NSString *imageURLHost = url.host;//获取图片URL的host
  131 + NSURL *newURL = url;
  132 + if (wself.enableHttpDNS && (imageURLHost.length > 0)) {
  133 + NSArray *ips = [[HttpDnsService sharedInstance] getIpsByHostAsync:imageURLHost];//同步请求ip地址列表
  134 + if ([ips isKindOfClass:[NSArray class]] && [ips respondsToSelector:@selector(count)] && ips.count > 0) {
  135 + NSString *ipAdress = [ips objectAtIndex:0];
  136 + NSString *urlString = [url absoluteString];
  137 + NSRange hostRange = [urlString rangeOfString:imageURLHost];
  138 + if ((NSNotFound != hostRange.location) && (ipAdress.length > 0)) {
  139 + useAliDNS = YES;
  140 + NSString *convertedURLString = [urlString stringByReplacingCharactersInRange:hostRange withString:ipAdress];//host转换之后的urlstring
  141 + newURL = [NSURL URLWithString:convertedURLString]; //替换原始url为转换后的值
  142 + }
159 } 143 }
160 } 144 }
161 - }  
162 145
163 - [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{  
164 - NSTimeInterval timeoutInterval = wself.downloadTimeout;  
165 - if (timeoutInterval == 0.0) {  
166 - timeoutInterval = 15.0;  
167 - } 146 + [wself addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{
  147 + NSTimeInterval timeoutInterval = wself.downloadTimeout;
  148 + if (timeoutInterval == 0.0) {
  149 + timeoutInterval = 15.0;
  150 + }
168 151
169 - // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise  
170 - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:newURL cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];  
171 - request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);  
172 - request.HTTPShouldUsePipelining = YES;  
173 - if (wself.headersFilter) {  
174 - request.allHTTPHeaderFields = wself.headersFilter(newURL, [wself.HTTPHeaders copy]);  
175 - }  
176 - else {  
177 - request.allHTTPHeaderFields = wself.HTTPHeaders;  
178 - }  
179 - if (useAliDNS) { //如果使用了DNS功能,要设置httpheader的host字段的值,否则请求失败  
180 - [request setValue:imageURLHost forHTTPHeaderField:@"host"];  
181 - }  
182 - operation = [[wself.operationClass alloc] initWithRequest:request  
183 - options:options  
184 - progress:^(NSInteger receivedSize, NSInteger expectedSize) {  
185 - SDWebImageDownloader *sself = wself;  
186 - if (!sself) return;  
187 - __block NSArray *callbacksForURL;  
188 - dispatch_sync(sself.barrierQueue, ^{  
189 - callbacksForURL = [sself.URLCallbacks[url] copy];  
190 - });  
191 - for (NSDictionary *callbacks in callbacksForURL) {  
192 - SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey];  
193 - if (callback) callback(receivedSize, expectedSize); 152 + // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
  153 + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:newURL cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];
  154 + request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
  155 + request.HTTPShouldUsePipelining = YES;
  156 + if (wself.headersFilter) {
  157 + request.allHTTPHeaderFields = wself.headersFilter(newURL, [wself.HTTPHeaders copy]);
  158 + }
  159 + else {
  160 + request.allHTTPHeaderFields = wself.HTTPHeaders;
  161 + }
  162 + if (useAliDNS) { //如果使用了DNS功能,要设置httpheader的host字段的值,否则请求失败
  163 + [request setValue:imageURLHost forHTTPHeaderField:@"Host"];
  164 + }
  165 + operation = [[wself.operationClass alloc] initWithRequest:request
  166 + options:options
  167 + progress:^(NSInteger receivedSize, NSInteger expectedSize) {
  168 + SDWebImageDownloader *sself = wself;
  169 + if (!sself) return;
  170 + __block NSArray *callbacksForURL;
  171 + dispatch_sync(sself.barrierQueue, ^{
  172 + callbacksForURL = [sself.URLCallbacks[url] copy];
  173 + });
  174 + for (NSDictionary *callbacks in callbacksForURL) {
  175 + SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey];
  176 + if (callback) callback(receivedSize, expectedSize);
  177 + }
194 } 178 }
195 - }  
196 - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {  
197 -// NSLog(@"download image completed:url == %@,\nimage = %@",url,image);  
198 - SDWebImageDownloader *sself = wself;  
199 - if (!sself) return;  
200 - __block NSArray *callbacksForURL;  
201 - dispatch_barrier_sync(sself.barrierQueue, ^{  
202 - callbacksForURL = [sself.URLCallbacks[url] copy];  
203 - if (finished) {  
204 - [sself.URLCallbacks removeObjectForKey:url]; 179 + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
  180 + // NSLog(@"download image completed:url == %@,\nimage = %@",url,image);
  181 + SDWebImageDownloader *sself = wself;
  182 + if (!sself) return;
  183 + __block NSArray *callbacksForURL;
  184 + dispatch_barrier_sync(sself.barrierQueue, ^{
  185 + callbacksForURL = [sself.URLCallbacks[url] copy];
  186 + if (finished) {
  187 + [sself.URLCallbacks removeObjectForKey:url];
  188 + }
  189 + });
  190 + for (NSDictionary *callbacks in callbacksForURL) {
  191 + SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];
  192 + if (callback) callback(image, data, error, finished);
205 } 193 }
206 - });  
207 - for (NSDictionary *callbacks in callbacksForURL) {  
208 - SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];  
209 - if (callback) callback(image, data, error, finished);  
210 } 194 }
211 - }  
212 - cancelled:^{  
213 - SDWebImageDownloader *sself = wself;  
214 - if (!sself) return;  
215 - dispatch_barrier_async(sself.barrierQueue, ^{  
216 - [sself.URLCallbacks removeObjectForKey:url];  
217 - });  
218 - }];  
219 - operation.shouldDecompressImages = wself.shouldDecompressImages;  
220 -  
221 - if (wself.username && wself.password) {  
222 - operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession];  
223 - }  
224 -  
225 - if (options & SDWebImageDownloaderHighPriority) {  
226 - operation.queuePriority = NSOperationQueuePriorityHigh;  
227 - } else if (options & SDWebImageDownloaderLowPriority) {  
228 - operation.queuePriority = NSOperationQueuePriorityLow;  
229 - } 195 + cancelled:^{
  196 + SDWebImageDownloader *sself = wself;
  197 + if (!sself) return;
  198 + dispatch_barrier_async(sself.barrierQueue, ^{
  199 + [sself.URLCallbacks removeObjectForKey:url];
  200 + });
  201 + }];
  202 + operation.shouldDecompressImages = wself.shouldDecompressImages;
  203 +
  204 + if (wself.username && wself.password) {
  205 + operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession];
  206 + }
  207 +
  208 + if (options & SDWebImageDownloaderHighPriority) {
  209 + operation.queuePriority = NSOperationQueuePriorityHigh;
  210 + } else if (options & SDWebImageDownloaderLowPriority) {
  211 + operation.queuePriority = NSOperationQueuePriorityLow;
  212 + }
230 213
231 - [wself.downloadQueue addOperation:operation];  
232 - if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {  
233 - // Emulate LIFO execution order by systematically adding new operations as last operation's dependency  
234 - [wself.lastAddedOperation addDependency:operation];  
235 - wself.lastAddedOperation = operation;  
236 - }  
237 - }]; 214 + [wself.downloadQueue addOperation:operation];
  215 + if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
  216 + // Emulate LIFO execution order by systematically adding new operations as last operation's dependency
  217 + [wself.lastAddedOperation addDependency:operation];
  218 + wself.lastAddedOperation = operation;
  219 + }
  220 + }];
  221 + });
238 222
239 return operation; 223 return operation;
240 } 224 }