Merge pull request #2852 from dreampiggy/fix_fifo_order_policy
Fix the LIFO order inverse issue when adding new urls during previous url query
This commit is contained in:
commit
46bdb3b8c1
|
@ -38,7 +38,6 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
||||||
@interface SDWebImageDownloader () <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
|
@interface SDWebImageDownloader () <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
|
||||||
|
|
||||||
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
|
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
|
||||||
@property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;
|
|
||||||
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, NSOperation<SDWebImageDownloaderOperation> *> *URLOperations;
|
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, NSOperation<SDWebImageDownloaderOperation> *> *URLOperations;
|
||||||
@property (strong, nonatomic, nullable) NSMutableDictionary<NSString *, NSString *> *HTTPHeaders;
|
@property (strong, nonatomic, nullable) NSMutableDictionary<NSString *, NSString *> *HTTPHeaders;
|
||||||
@property (strong, nonatomic, nonnull) dispatch_semaphore_t HTTPHeadersLock; // A lock to keep the access to `HTTPHeaders` thread-safe
|
@property (strong, nonatomic, nonnull) dispatch_semaphore_t HTTPHeadersLock; // A lock to keep the access to `HTTPHeaders` thread-safe
|
||||||
|
@ -321,9 +320,12 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.config.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
|
if (self.config.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
|
||||||
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
|
// Emulate LIFO execution order by systematically, each previous adding operation can dependency the new operation
|
||||||
[self.lastAddedOperation addDependency:operation];
|
// This can gurantee the new operation to be execulated firstly, even if when some operations finished, meanwhile you appending new operations
|
||||||
self.lastAddedOperation = operation;
|
// Just make last added operation dependents new operation can not solve this problem. See test case #test15DownloaderLIFOExecutionOrder
|
||||||
|
for (NSOperation *pendingOperation in self.downloadQueue.operations) {
|
||||||
|
[pendingOperation addDependency:operation];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
@interface SDWebImageDownloaderTests : SDTestCase
|
@interface SDWebImageDownloaderTests : SDTestCase
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSMutableArray<NSURL *> *executionOrderURLs;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation SDWebImageDownloaderTests
|
@implementation SDWebImageDownloaderTests
|
||||||
|
@ -250,6 +252,91 @@
|
||||||
[self waitForExpectationsWithCommonTimeout];
|
[self waitForExpectationsWithCommonTimeout];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)test15DownloaderLIFOExecutionOrder {
|
||||||
|
SDWebImageDownloaderConfig *config = [[SDWebImageDownloaderConfig alloc] init];
|
||||||
|
config.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; // Last In First Out
|
||||||
|
config.maxConcurrentDownloads = 1; // 1
|
||||||
|
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] initWithConfig:config];
|
||||||
|
self.executionOrderURLs = [NSMutableArray array];
|
||||||
|
|
||||||
|
// Input order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 (wait for 7 finished and immediately) -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14
|
||||||
|
// Expected result: 1 (first one has no dependency) -> 7 -> 14 -> 13 -> 12 -> 11 -> 10 -> 9 -> 8 -> 6 -> 5 -> 4 -> 3 -> 2
|
||||||
|
int waitIndex = 7;
|
||||||
|
int maxIndex = 14;
|
||||||
|
NSMutableArray<XCTestExpectation *> *expectations = [NSMutableArray array];
|
||||||
|
for (int i = 1; i <= maxIndex; i++) {
|
||||||
|
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"URL %d order wrong", i]];
|
||||||
|
[expectations addObject:expectation];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= waitIndex; i++) {
|
||||||
|
[self createLIFOOperationWithDownloader:downloader expectation:expectations[i-1] index:i];
|
||||||
|
}
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:SDWebImageDownloadFinishNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
|
||||||
|
SDWebImageDownloaderOperation *operation = note.object;
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", waitIndex]];
|
||||||
|
if (![operation.request.URL isEqual:url]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = waitIndex + 1; i <= maxIndex; i++) {
|
||||||
|
[self createLIFOOperationWithDownloader:downloader expectation:expectations[i-1] index:i];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self waitForExpectationsWithTimeout:kAsyncTestTimeout * maxIndex handler:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wshadow"
|
||||||
|
- (void)createLIFOOperationWithDownloader:(SDWebImageDownloader *)downloader expectation:(XCTestExpectation *)expectation index:(int)index {
|
||||||
|
int waitIndex = 7;
|
||||||
|
int maxIndex = 14;
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", index]];
|
||||||
|
[self.executionOrderURLs addObject:url];
|
||||||
|
[downloader downloadImageWithURL:url options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", waitIndex]];
|
||||||
|
if ([self.executionOrderURLs containsObject:url]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||||
|
printf("URL%d finished\n", index);
|
||||||
|
NSMutableArray *pendingArray = [NSMutableArray array];
|
||||||
|
if (index == 1) {
|
||||||
|
// 1
|
||||||
|
for (int j = 1; j <= waitIndex; j++) {
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", j]];
|
||||||
|
[pendingArray addObject:url];
|
||||||
|
}
|
||||||
|
} else if (index == waitIndex) {
|
||||||
|
// 7
|
||||||
|
for (int j = 2; j <= maxIndex; j++) {
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", j]];
|
||||||
|
[pendingArray addObject:url];
|
||||||
|
}
|
||||||
|
} else if (index > waitIndex) {
|
||||||
|
// 8-14
|
||||||
|
for (int j = 2; j <= index; j++) {
|
||||||
|
if (j == waitIndex) continue;
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", j]];
|
||||||
|
[pendingArray addObject:url];
|
||||||
|
}
|
||||||
|
} else if (index < waitIndex) {
|
||||||
|
// 2-6
|
||||||
|
for (int j = 2; j <= index; j++) {
|
||||||
|
if (j == waitIndex) continue;
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", j]];
|
||||||
|
[pendingArray addObject:url];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(self.executionOrderURLs).equal(pendingArray);
|
||||||
|
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://via.placeholder.com/1000x%d.png", index]];
|
||||||
|
[self.executionOrderURLs removeObject:url];
|
||||||
|
[expectation fulfill];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
- (void)test17ThatMinimumProgressIntervalWorks {
|
- (void)test17ThatMinimumProgressIntervalWorks {
|
||||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"];
|
XCTestExpectation *expectation = [self expectationWithDescription:@"Minimum progress interval"];
|
||||||
SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig;
|
SDWebImageDownloaderConfig *config = SDWebImageDownloaderConfig.defaultDownloaderConfig;
|
||||||
|
|
Loading…
Reference in New Issue