Merge pull request #2631 from dreampiggy/bugfix_prefetch_concurrent_query_cache

Fix the issue that SDWebImagePrefetch in 5.x, will submit all prefetch URLs to manager without any concurrent limit
This commit is contained in:
Kinarobin 2019-03-09 13:40:08 +08:00 committed by GitHub
commit 78e408c537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 155 additions and 34 deletions

View File

@ -28,8 +28,9 @@ Pod::Spec.new do |s|
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h'
core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h', 'SDWebImage/Private/*.{h,m}'
core.exclude_files = 'SDWebImage/MapKit/*.{h,m}'
core.private_header_files = 'SDWebImage/Private/*.h'
end
s.subspec 'MapKit' do |mk|

View File

@ -91,6 +91,10 @@
329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; };
329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; };
329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */; };
32B5CC60222F89C2005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
32B5CC61222F89C2005EB74E /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */; };
32B5CC62222F89F6005EB74E /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */; };
32B9B537206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */; };
@ -269,6 +273,8 @@
3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = "<group>"; };
329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Metadata.h"; sourceTree = "<group>"; };
329A18581FFF5DFD008C9A2F /* UIImage+Metadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Metadata.m"; sourceTree = "<group>"; };
32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = "<group>"; };
32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.m; sourceTree = "<group>"; };
32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = "<group>"; };
32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderConfig.m; sourceTree = "<group>"; };
32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageIndicator.h; sourceTree = "<group>"; };
@ -438,6 +444,15 @@
name = Transformer;
sourceTree = "<group>";
};
32B5CC5D222F89C2005EB74E /* Private */ = {
isa = PBXGroup;
children = (
32B5CC5E222F89C2005EB74E /* SDAsyncBlockOperation.h */,
32B5CC5F222F89C2005EB74E /* SDAsyncBlockOperation.m */,
);
path = Private;
sourceTree = "<group>";
};
32FDE8792088871B008D7530 /* MapKit */ = {
isa = PBXGroup;
children = (
@ -530,6 +545,7 @@
53922DAC148C56DD0056699D /* Utils */,
53922DA9148C562D0056699D /* Categories */,
4369C2851D9811BB007E863A /* WebCache Categories */,
32B5CC5D222F89C2005EB74E /* Private */,
32FDE8792088871B008D7530 /* MapKit */,
);
path = SDWebImage;
@ -633,6 +649,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
32B5CC60222F89C2005EB74E /* SDAsyncBlockOperation.h in Headers */,
32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */,
32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */,
@ -690,6 +707,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
32B5CC62222F89F6005EB74E /* SDAsyncBlockOperation.h in Headers */,
32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */,
32F7C0842030719600873181 /* UIImage+Transform.h in Headers */,
3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */,
@ -896,6 +914,7 @@
32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */,
3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */,
32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
32B5CC61222F89C2005EB74E /* SDAsyncBlockOperation.m in Sources */,
32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */,
4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */,
@ -951,6 +970,7 @@
32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */,
3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */,
32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */,
32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */,
321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */,

View File

@ -0,0 +1,20 @@
/*
* 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 "SDWebImageCompat.h"
@class SDAsyncBlockOperation;
typedef void (^SDAsyncBlock)(SDAsyncBlockOperation * __nonnull asyncOperation);
@interface SDAsyncBlockOperation : NSOperation
- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block;
+ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block;
- (void)complete;
@end

View File

@ -0,0 +1,55 @@
/*
* 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 "SDAsyncBlockOperation.h"
@interface SDAsyncBlockOperation ()
@property (nonatomic, assign) BOOL isExecuting;
@property (nonatomic, assign) BOOL isFinished;
@property (nonatomic, copy, nonnull) SDAsyncBlock executionBlock;
@end
@implementation SDAsyncBlockOperation
- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block {
self = [super init];
if (self) {
self.executionBlock = block;
}
return self;
}
+ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block {
SDAsyncBlockOperation *operation = [[SDAsyncBlockOperation alloc] initWithBlock:block];
return operation;
}
- (void)start {
[self willChangeValueForKey:@"isExecuting"];
self.isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
if (self.executionBlock) {
self.executionBlock(self);
} else {
[self complete];
}
}
- (void)complete {
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.isExecuting = NO;
self.isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
@end

View File

@ -63,6 +63,11 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls,
*/
@property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager;
/**
* Maximum number of URLs to prefetch at the same time. Defaults to 3.
*/
@property (nonatomic, assign) NSUInteger maxConcurrentPrefetchCount;
/**
* The options for prefetcher. Defaults to SDWebImageLowPriority.
*/

View File

@ -7,6 +7,7 @@
*/
#import "SDWebImagePrefetcher.h"
#import "SDAsyncBlockOperation.h"
#import <stdatomic.h>
@interface SDWebImagePrefetchToken () {
@ -32,6 +33,7 @@
@property (strong, nonatomic, nonnull) SDWebImageManager *manager;
@property (strong, atomic, nonnull) NSMutableSet<SDWebImagePrefetchToken *> *runningTokens;
@property (strong, nonatomic, nonnull) NSOperationQueue *prefetchQueue;
@end
@ -56,10 +58,20 @@
_runningTokens = [NSMutableSet set];
_options = SDWebImageLowPriority;
_delegateQueue = dispatch_get_main_queue();
_prefetchQueue = [NSOperationQueue new];
self.maxConcurrentPrefetchCount = 3;
}
return self;
}
- (void)setMaxConcurrentPrefetchCount:(NSUInteger)maxConcurrentPrefetchCount {
self.prefetchQueue.maxConcurrentOperationCount = maxConcurrentPrefetchCount;
}
- (NSUInteger)maxConcurrentPrefetchCount {
return self.prefetchQueue.maxConcurrentOperationCount;
}
#pragma mark - Prefetch
- (nullable SDWebImagePrefetchToken *)prefetchURLs:(nullable NSArray<NSURL *> *)urls {
return [self prefetchURLs:urls progress:nil completed:nil];
@ -85,43 +97,51 @@
token.progressBlock = progressBlock;
token.completionBlock = completionBlock;
[self addRunningToken:token];
NSPointerArray *operations = token.operations;
for (NSURL *url in urls) {
__weak typeof(self) wself = self;
id<SDWebImageOperation> operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
__strong typeof(wself) sself = wself;
if (!sself) {
return;
}
if (!finished) {
return;
}
atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed);
if (error) {
// Add last failed
atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed);
}
// Current operation finished
[sself callProgressBlockForToken:token imageURL:imageURL];
if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) {
// All finished
if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) {
[sself callCompletionBlockForToken:token];
[sself removeRunningToken:token];
}
}
}];
@synchronized (token) {
[operations addPointer:(__bridge void *)operation];
}
}
[self startPrefetchWithToken:token];
return token;
}
- (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token {
NSPointerArray *operations = token.operations;
for (NSURL *url in token.urls) {
__weak typeof(self) wself = self;
SDAsyncBlockOperation *prefetchOperation = [SDAsyncBlockOperation blockOperationWithBlock:^(SDAsyncBlockOperation * _Nonnull asyncOperation) {
id<SDWebImageOperation> operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
__strong typeof(wself) sself = wself;
if (!sself) {
return;
}
if (!finished) {
return;
}
[asyncOperation complete];
atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed);
if (error) {
// Add last failed
atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed);
}
// Current operation finished
[sself callProgressBlockForToken:token imageURL:imageURL];
if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) {
// All finished
if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) {
[sself callCompletionBlockForToken:token];
[sself removeRunningToken:token];
}
}
}];
@synchronized (token) {
[operations addPointer:(__bridge void *)operation];
}
}];
[self.prefetchQueue addOperation:prefetchOperation];
}
}
#pragma mark - Cancel
- (void)cancelPrefetching {
@synchronized(self.runningTokens) {