Fix the issue that SDWebImagePrefetch in 5.x, will submit all prefetch URLs to manager without any limit, which cause the disk cache query pending until all finished
Because they are implementation details, we can not always assume the cache and downloader use a load balancing algorithm
This commit is contained in:
parent
537affb9af
commit
2ce3b706c8
|
@ -87,6 +87,10 @@
|
|||
3290FA061FA478AF0047D20C /* SDImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3290FA0A1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; };
|
||||
3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 3290FA031FA478AF0047D20C /* SDImageFrame.m */; };
|
||||
3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; };
|
||||
3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */; };
|
||||
329A18591FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
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 */; };
|
||||
|
@ -267,6 +271,8 @@
|
|||
328BB6C02082581100760D6C /* SDMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDMemoryCache.m; sourceTree = "<group>"; };
|
||||
3290FA021FA478AF0047D20C /* SDImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageFrame.h; sourceTree = "<group>"; };
|
||||
3290FA031FA478AF0047D20C /* SDImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDImageFrame.m; sourceTree = "<group>"; };
|
||||
3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAsyncBlockOperation.h; sourceTree = "<group>"; };
|
||||
3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAsyncBlockOperation.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>"; };
|
||||
32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderConfig.h; sourceTree = "<group>"; };
|
||||
|
@ -425,6 +431,8 @@
|
|||
children = (
|
||||
53922D91148C56230056699D /* SDWebImagePrefetcher.h */,
|
||||
53922D92148C56230056699D /* SDWebImagePrefetcher.m */,
|
||||
3299C4EC222BC3FD00DABA0F /* SDAsyncBlockOperation.h */,
|
||||
3299C4ED222BC3FD00DABA0F /* SDAsyncBlockOperation.m */,
|
||||
);
|
||||
name = Prefetcher;
|
||||
sourceTree = "<group>";
|
||||
|
@ -633,6 +641,7 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3299C4EF222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */,
|
||||
32D122202080B2EB003685A3 /* SDImageCacheDefine.h in Headers */,
|
||||
32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
|
||||
3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */,
|
||||
|
@ -690,6 +699,7 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3299C4EE222BC3FD00DABA0F /* SDAsyncBlockOperation.h in Headers */,
|
||||
32CF1C071FA496B000004BD1 /* SDImageCoderHelper.h in Headers */,
|
||||
32F7C0842030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
3257EAF921898AED0097B271 /* SDImageGraphics.h in Headers */,
|
||||
|
@ -896,6 +906,7 @@
|
|||
32F7C0772030114C00873181 /* SDImageTransformer.m in Sources */,
|
||||
3237F9E820161AE000A88143 /* NSImage+Compatibility.m in Sources */,
|
||||
32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
|
||||
3299C4F1222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */,
|
||||
32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
|
||||
321B37952083290E00C0EA77 /* SDImageLoadersManager.m in Sources */,
|
||||
4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */,
|
||||
|
@ -951,6 +962,7 @@
|
|||
32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */,
|
||||
3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */,
|
||||
32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
|
||||
3299C4F0222BC3FD00DABA0F /* SDAsyncBlockOperation.m in Sources */,
|
||||
32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
|
||||
5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */,
|
||||
321B37932083290E00C0EA77 /* SDImageLoadersManager.m in Sources */,
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue