Merge pull request #3477 from dreampiggy/bugfix/ensure_downloader_callback_atomic
Ensure the Downloader and DownloaderOperation callback the completion in atomic and never miss one
This commit is contained in:
commit
a052164350
|
@ -74,7 +74,7 @@
|
|||
@"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
|
||||
@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png",
|
||||
@"https://res.cloudinary.com/dwpjzbyux/raw/upload/v1666474070/RawDemo/raw_vebed5.NEF",
|
||||
@"http://via.placeholder.com/200x200.jpg",
|
||||
@"https://via.placeholder.com/200x200.jpg",
|
||||
nil];
|
||||
|
||||
for (int i=1; i<25; i++) {
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
if (!_fetchQueue) {
|
||||
_fetchQueue = [[NSOperationQueue alloc] init];
|
||||
_fetchQueue.maxConcurrentOperationCount = 1;
|
||||
_fetchQueue.name = @"com.hackemist.SDAnimatedImagePlayer.fetchQueue";
|
||||
}
|
||||
return _fetchQueue;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ static NSString * _defaultDiskCacheDirectory;
|
|||
@property (nonatomic, strong, readwrite, nonnull) id<SDDiskCache> diskCache;
|
||||
@property (nonatomic, copy, readwrite, nonnull) SDImageCacheConfig *config;
|
||||
@property (nonatomic, copy, readwrite, nonnull) NSString *diskCachePath;
|
||||
@property (nonatomic, strong, nullable) dispatch_queue_t ioQueue;
|
||||
@property (nonatomic, strong, nonnull) dispatch_queue_t ioQueue;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -118,7 +118,7 @@ static NSString * _defaultDiskCacheDirectory;
|
|||
|
||||
// Create IO queue
|
||||
dispatch_queue_attr_t ioQueueAttributes = _config.ioQueueAttributes;
|
||||
_ioQueue = dispatch_queue_create("com.hackemist.SDImageCache", ioQueueAttributes);
|
||||
_ioQueue = dispatch_queue_create("com.hackemist.SDImageCache.ioQueue", ioQueueAttributes);
|
||||
NSAssert(_ioQueue, @"The IO queue should not be nil. Your configured `ioQueueAttributes` may be wrong");
|
||||
|
||||
// Init the memory cache
|
||||
|
@ -508,10 +508,6 @@ static NSString * _defaultDiskCacheDirectory;
|
|||
|
||||
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key {
|
||||
NSData *data = [self diskImageDataForKey:key];
|
||||
return [self diskImageForKey:key data:data];
|
||||
}
|
||||
|
||||
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data {
|
||||
return [self diskImageForKey:key data:data options:0 context:nil];
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#import "SDWebImageCacheKeyFilter.h"
|
||||
#import "SDImageCacheDefine.h"
|
||||
#import "SDInternalMacros.h"
|
||||
#import "objc/runtime.h"
|
||||
|
||||
NSNotificationName const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification";
|
||||
NSNotificationName const SDWebImageDownloadReceiveResponseNotification = @"SDWebImageDownloadReceiveResponseNotification";
|
||||
|
@ -20,6 +21,22 @@ NSNotificationName const SDWebImageDownloadStopNotification = @"SDWebImageDownlo
|
|||
NSNotificationName const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinishNotification";
|
||||
|
||||
static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
||||
static void * SDWebImageDownloaderOperationKey = &SDWebImageDownloaderOperationKey;
|
||||
|
||||
BOOL SDWebImageDownloaderOperationGetCompleted(id<SDWebImageDownloaderOperation> operation) {
|
||||
NSCParameterAssert(operation);
|
||||
NSNumber *value = objc_getAssociatedObject(operation, SDWebImageDownloaderOperationKey);
|
||||
if (value) {
|
||||
return value.boolValue;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
void SDWebImageDownloaderOperationSetCompleted(id<SDWebImageDownloaderOperation> operation, BOOL isCompleted) {
|
||||
NSCParameterAssert(operation);
|
||||
objc_setAssociatedObject(operation, SDWebImageDownloaderOperationKey, @(isCompleted), OBJC_ASSOCIATION_RETAIN);
|
||||
}
|
||||
|
||||
@interface SDWebImageDownloadToken ()
|
||||
|
||||
|
@ -99,7 +116,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
[_config addObserver:self forKeyPath:NSStringFromSelector(@selector(maxConcurrentDownloads)) options:0 context:SDWebImageDownloaderContext];
|
||||
_downloadQueue = [NSOperationQueue new];
|
||||
_downloadQueue.maxConcurrentOperationCount = _config.maxConcurrentDownloads;
|
||||
_downloadQueue.name = @"com.hackemist.SDWebImageDownloader";
|
||||
_downloadQueue.name = @"com.hackemist.SDWebImageDownloader.downloadQueue";
|
||||
_URLOperations = [NSMutableDictionary new];
|
||||
NSMutableDictionary<NSString *, NSString *> *headerDictionary = [NSMutableDictionary dictionary];
|
||||
NSString *userAgent = nil;
|
||||
|
@ -219,7 +236,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
SDImageCoderOptions *decodeOptions = SDGetDecodeOptionsFromContext(context, [self.class imageOptionsFromDownloaderOptions:options], cacheKey);
|
||||
NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
|
||||
// There is a case that the operation may be marked as finished or cancelled, but not been removed from `self.URLOperations`.
|
||||
if (!operation || operation.isFinished || operation.isCancelled) {
|
||||
BOOL shouldNotReuseOperation = !operation || operation.isFinished || operation.isCancelled || SDWebImageDownloaderOperationGetCompleted(operation);
|
||||
if (shouldNotReuseOperation) {
|
||||
operation = [self createDownloaderOperationWithUrl:url options:options context:context];
|
||||
if (!operation) {
|
||||
SD_UNLOCK(_operationsLock);
|
||||
|
@ -499,6 +517,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
|
||||
// Identify the operation that runs this task and pass it the delegate method
|
||||
NSOperation<SDWebImageDownloaderOperation> *dataOperation = [self operationWithTask:task];
|
||||
if (dataOperation) {
|
||||
// Mark the downloader operation `isCompleted = YES`, no longer re-use this operation when new request comes in
|
||||
SDWebImageDownloaderOperationSetCompleted(dataOperation, true);
|
||||
}
|
||||
if ([dataOperation respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]) {
|
||||
[dataOperation URLSession:session task:task didCompleteWithError:error];
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#import "SDImageCacheDefine.h"
|
||||
#import "SDCallbackQueue.h"
|
||||
|
||||
BOOL SDWebImageDownloaderOperationGetCompleted(id<SDWebImageDownloaderOperation> operation); // Private currently, mark open if needed
|
||||
|
||||
// A handler to represent individual request
|
||||
@interface SDWebImageDownloaderOperationToken : NSObject
|
||||
|
||||
|
@ -110,8 +112,9 @@
|
|||
_finished = NO;
|
||||
_expectedSize = 0;
|
||||
_unownedSession = session;
|
||||
_coderQueue = [NSOperationQueue new];
|
||||
_coderQueue = [[NSOperationQueue alloc] init];
|
||||
_coderQueue.maxConcurrentOperationCount = 1;
|
||||
_coderQueue.name = @"com.hackemist.SDWebImageDownloaderOperation.coderQueue";
|
||||
_imageMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:1];
|
||||
#if SD_UIKIT
|
||||
_backgroundTaskId = UIBackgroundTaskInvalid;
|
||||
|
@ -231,13 +234,10 @@
|
|||
if (self.dataTask) {
|
||||
if (self.options & SDWebImageDownloaderHighPriority) {
|
||||
self.dataTask.priority = NSURLSessionTaskPriorityHigh;
|
||||
self.coderQueue.qualityOfService = NSQualityOfServiceUserInteractive;
|
||||
} else if (self.options & SDWebImageDownloaderLowPriority) {
|
||||
self.dataTask.priority = NSURLSessionTaskPriorityLow;
|
||||
self.coderQueue.qualityOfService = NSQualityOfServiceBackground;
|
||||
} else {
|
||||
self.dataTask.priority = NSURLSessionTaskPriorityDefault;
|
||||
self.coderQueue.qualityOfService = NSQualityOfServiceDefault;
|
||||
}
|
||||
[self.dataTask resume];
|
||||
NSArray<SDWebImageDownloaderOperationToken *> *tokens;
|
||||
|
@ -471,22 +471,22 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
if (self.coderQueue.operationCount == 0) {
|
||||
// NSOperation have autoreleasepool, don't need to create extra one
|
||||
@weakify(self);
|
||||
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
|
||||
[self.coderQueue addOperationWithBlock:^{
|
||||
@strongify(self);
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, NO, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
||||
if (self.isFinished) {
|
||||
// When cancelled or transfer finished (`didCompleteWithError`), cancel the progress callback, only completed block is called and enough
|
||||
if (self.isCancelled || SDWebImageDownloaderOperationGetCompleted(self)) {
|
||||
return;
|
||||
}
|
||||
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, NO, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
||||
if (image) {
|
||||
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
|
||||
|
||||
[self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO];
|
||||
}
|
||||
}];
|
||||
[self.coderQueue addOperation:operation];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,16 +564,8 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
// decode the image in coder queue, cancel all previous decoding process
|
||||
[self.coderQueue cancelAllOperations];
|
||||
@weakify(self);
|
||||
// call done after all different variant completed block was dispatched
|
||||
NSOperation *doneOperation = [NSBlockOperation blockOperationWithBlock:^{
|
||||
@strongify(self);
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
[self done];
|
||||
}];
|
||||
for (SDWebImageDownloaderOperationToken *token in tokens) {
|
||||
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
|
||||
[self.coderQueue addOperationWithBlock:^{
|
||||
@strongify(self);
|
||||
if (!self) {
|
||||
return;
|
||||
|
@ -612,11 +604,22 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
[self callCompletionBlockWithToken:token image:image imageData:imageData error:nil finished:YES];
|
||||
}
|
||||
}];
|
||||
[doneOperation addDependency:operation];
|
||||
[self.coderQueue addOperation:operation];
|
||||
}
|
||||
// call [self done] after all completed block was dispatched
|
||||
[self.coderQueue addOperation:doneOperation];
|
||||
dispatch_block_t doneBlock = ^{
|
||||
@strongify(self);
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
[self done];
|
||||
};
|
||||
if (@available(iOS 13, tvOS 13, macOS 10.15, watchOS 6, *)) {
|
||||
// seems faster than `addOperationWithBlock`
|
||||
[self.coderQueue addBarrierBlock:doneBlock];
|
||||
} else {
|
||||
// serial queue, this does the same effect in semantics
|
||||
[self.coderQueue addOperationWithBlock:doneBlock];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]];
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
const int64_t kAsyncTestTimeout = 5;
|
||||
const int64_t kMinDelayNanosecond = NSEC_PER_MSEC * 100; // 0.1s
|
||||
NSString *const kTestJPEGURL = @"http://via.placeholder.com/50x50.jpg";
|
||||
NSString *const kTestJPEGURL = @"https://via.placeholder.com/50x50.jpg";
|
||||
NSString *const kTestProgressiveJPEGURL = @"https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_progressive.jpg";
|
||||
NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png";
|
||||
NSString *const kTestPNGURL = @"https://via.placeholder.com/50x50.png";
|
||||
NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif";
|
||||
NSString *const kTestAPNGPURL = @"https://upload.wikimedia.org/wikipedia/commons/1/14/Animated_PNG_example_bouncing_beach_ball.png";
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@
|
|||
- (void)test11ThatCancelWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://via.placeholder.com/1000x1000.png"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"https://via.placeholder.com/1000x1000.png"];
|
||||
SDWebImageDownloadToken *token = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).notTo.beNil();
|
||||
|
@ -680,7 +680,7 @@
|
|||
expect(metric.fetchStartDate).notTo.beNil();
|
||||
expect(metric.connectStartDate).notTo.beNil();
|
||||
expect(metric.connectEndDate).notTo.beNil();
|
||||
expect(metric.networkProtocolName).equal(@"http/1.1");
|
||||
expect(metric.networkProtocolName).equal(@"h2");
|
||||
expect(metric.resourceFetchType).equal(NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad);
|
||||
expect(metric.isProxyConnection).beFalsy();
|
||||
expect(metric.isReusedConnection).beFalsy();
|
||||
|
@ -779,7 +779,7 @@
|
|||
// We move the logic into SDWebImageDownloaderOperation, which decode each callback's thumbnail size with different decoding pipeline, and callback independently
|
||||
// Note the progressiveLoad does not support this and always callback first size
|
||||
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/501x501.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/501x501.png"];
|
||||
NSString *fullSizeKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
[SDImageCache.sharedImageCache removeImageFromDiskForKey:fullSizeKey];
|
||||
for (int i = 490; i < 500; i++) {
|
||||
|
@ -799,8 +799,39 @@
|
|||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout * 5 handler:nil];
|
||||
}
|
||||
|
||||
- (void)test31ThatMultipleRequestForSameURLNeverSkipCallback {
|
||||
// See #3475
|
||||
// When multiple download request for same URL, the SDWebImageDownloader will try to `Re-use` URLSessionTask to avoid duplicate actual network request
|
||||
// However, if caller submit too frequently in another queue, we should stop attaching more callback once the URLSessionTask `didCompleteWithError:` is called
|
||||
NSURL *url = [NSURL fileURLWithPath:[self testPNGPath]];
|
||||
NSMutableArray<XCTestExpectation *> *expectations = [NSMutableArray arrayWithCapacity:100];
|
||||
__block void (^recursiveBlock)(int);
|
||||
void (^mainBlock)(int) = ^(int i) {
|
||||
if (i > 200) return;
|
||||
NSString *desc = [NSString stringWithFormat:@"Local url with index %d not callback!", i];
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:desc];
|
||||
[expectations addObject:expectation];
|
||||
// Delay 0.01s ~ 0.99s for each download request, simulate the real-world call site
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(i * 10000000ull)), dispatch_get_main_queue(), ^{
|
||||
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:url completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image) {
|
||||
NSLog(@"Local url callback with index: %d", i);
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong: %@", error.description);
|
||||
}
|
||||
}];
|
||||
});
|
||||
recursiveBlock(i+1);
|
||||
};
|
||||
recursiveBlock = mainBlock;
|
||||
recursiveBlock(0);
|
||||
|
||||
[self waitForExpectations:expectations timeout:kAsyncTestTimeout * 2];
|
||||
}
|
||||
|
||||
#pragma mark - SDWebImageLoader
|
||||
- (void)test30CustomImageLoaderWorks {
|
||||
- (void)testCustomImageLoaderWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"];
|
||||
SDWebImageTestLoader *loader = [[SDWebImageTestLoader alloc] init];
|
||||
NSURL *imageURL = [NSURL URLWithString:kTestJPEGURL];
|
||||
|
@ -820,7 +851,7 @@
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test31ThatLoadersManagerWorks {
|
||||
- (void)testThatLoadersManagerWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Loaders manager not works"];
|
||||
SDWebImageTestLoader *loader = [[SDWebImageTestLoader alloc] init];
|
||||
SDImageLoadersManager *manager = [[SDImageLoadersManager alloc] init];
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
|
||||
- (void)test07ThatLoadImageWithSDWebImageRefreshCachedWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image download twice with SDWebImageRefresh failed"];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"http://via.placeholder.com/10x10.png"];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://via.placeholder.com/10x10.png"];
|
||||
__block BOOL firstCompletion = NO;
|
||||
[[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
|
@ -115,7 +115,7 @@
|
|||
// Because we call completion before remove the operation from queue, so need a dispatch to avoid get the same operation again. Attention this trap.
|
||||
// One way to solve this is use another `NSURL instance` because we use `NSURL` as key but not `NSString`. However, this is implementation detail and no guarantee in the future.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSURL *newImageURL = [NSURL URLWithString:@"http://via.placeholder.com/10x10.png"];
|
||||
NSURL *newImageURL = [NSURL URLWithString:@"https://via.placeholder.com/10x10.png"];
|
||||
[[SDWebImageManager sharedManager] loadImageWithURL:newImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage * _Nullable image2, NSData * _Nullable data2, NSError * _Nullable error2, SDImageCacheType cacheType2, BOOL finished2, NSURL * _Nullable imageURL2) {
|
||||
expect(image2).toNot.beNil();
|
||||
expect(error2).to.beNil();
|
||||
|
@ -132,7 +132,7 @@
|
|||
|
||||
- (void)test08ThatImageTransformerWork {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/80x60.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/80x60.png"];
|
||||
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
|
||||
|
||||
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
|
||||
|
@ -293,7 +293,7 @@
|
|||
|
||||
- (void)test13ThatScaleDownLargeImageUseThumbnailDecoding {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageScaleDownLargeImages should translate to thumbnail decoding"];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"http://via.placeholder.com/3999x3999.png"]; // Max size for this API
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://via.placeholder.com/2000x2000.png"]; // Max size for this API
|
||||
NSUInteger defaultLimitBytes = SDImageCoderHelper.defaultScaleDownLimitBytes;
|
||||
SDImageCoderHelper.defaultScaleDownLimitBytes = 1000 * 1000 * 4; // Limit 1000x1000 pixel
|
||||
// From v5.5.0, the `SDWebImageScaleDownLargeImages` translate to `SDWebImageContextImageThumbnailPixelSize`, and works for progressive loading
|
||||
|
@ -336,7 +336,7 @@
|
|||
|
||||
- (void)test14ThatCustomCacheAndLoaderWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Custom Cache and Loader during manger query"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/100x100.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/100x100.png"];
|
||||
SDWebImageContext *context = @{
|
||||
SDWebImageContextImageCache : SDWebImageTestCache.sharedCache,
|
||||
SDWebImageContextImageLoader : SDWebImageTestLoader.sharedLoader
|
||||
|
@ -360,7 +360,7 @@
|
|||
|
||||
- (void)test15ThatQueryCacheTypeWork {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image query cache type works"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/101x101.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/101x101.png"];
|
||||
NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
NSData *testImageData = [NSData dataWithContentsOfFile:[self testJPEGPath]];
|
||||
[SDImageCache.sharedImageCache storeImageDataToDisk:testImageData forKey:key];
|
||||
|
@ -383,7 +383,7 @@
|
|||
|
||||
- (void)test15ThatOriginalQueryCacheTypeWork {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image original query cache type with transformer works"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/102x102.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/102x102.png"];
|
||||
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
|
||||
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
|
||||
NSString *originalKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
|
@ -419,7 +419,7 @@
|
|||
|
||||
- (void)test16ThatTransformerUseDifferentCacheForOriginalAndTransformedImage {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer use different cache instance for original image and transformed image works"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/103x103.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/103x103.png"];
|
||||
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
|
||||
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
|
||||
NSString *originalKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
|
@ -505,7 +505,7 @@
|
|||
CGContextFillRect(context, CGRectMake(0, 0, fullSize.width, fullSize.height));
|
||||
}];
|
||||
expect(fullSizeImage.size).equal(fullSize);
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/500x500.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/500x500.png"];
|
||||
NSString *fullSizeKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
NSData *fullSizeData = fullSizeImage.sd_imageData;
|
||||
[SDImageCache.sharedImageCache storeImageDataToDisk:fullSizeData forKey:fullSizeKey];
|
||||
|
@ -535,7 +535,7 @@
|
|||
// We move the logic into SDWebImageDownloaderOperation, which decode each callback's thumbnail size with different decoding pipeline, and callback independently
|
||||
// Note the progressiveLoad does not support this and always callback first size
|
||||
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/501x501.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/501x501.png"];
|
||||
NSString *fullSizeKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
|
||||
[SDImageCache.sharedImageCache removeImageFromDiskForKey:fullSizeKey];
|
||||
for (int i = 490; i < 500; i++) {
|
||||
|
@ -563,7 +563,7 @@
|
|||
|
||||
- (void)test20ThatContextPassDecodeOptionsWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"The SDWebImageContextImageDecodeOptions should passed to the coder"];
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/502x502.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/502x502.png"];
|
||||
SDImageCoderOptions *originalDecodeOptions = @{@"Foo": @"Bar", SDImageCoderDecodeScaleFactor : @(2)}; // This will be override
|
||||
|
||||
[SDWebImageManager.sharedManager loadImageWithURL:url options:0 context:@{SDWebImageContextImageScaleFactor : @(1), SDWebImageContextImageDecodeOptions : originalDecodeOptions} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
|
@ -579,7 +579,7 @@
|
|||
- (void)test21ThatQueryOriginalDiskCacheFromThumbnailShouldNotWriteBackDiskCache {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Using original disk cache to do thumbnail decoding or transformer, should not save back disk data again"];
|
||||
|
||||
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/503x503.png"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://via.placeholder.com/503x503.png"];
|
||||
NSString *originalKey = url.absoluteString;
|
||||
// 1. Store the disk data to original cache
|
||||
CGSize fullSize = CGSizeMake(503, 503);
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
- (void)test02PrefetchMultipleImages {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct prefetch of multiple images"];
|
||||
|
||||
NSArray *imageURLs = @[@"http://via.placeholder.com/20x20.jpg",
|
||||
@"http://via.placeholder.com/30x30.jpg",
|
||||
@"http://via.placeholder.com/40x40.jpg"];
|
||||
NSArray *imageURLs = @[@"https://via.placeholder.com/20x20.jpg",
|
||||
@"https://via.placeholder.com/30x30.jpg",
|
||||
@"https://via.placeholder.com/40x40.jpg"];
|
||||
|
||||
__block NSUInteger numberOfPrefetched = 0;
|
||||
|
||||
|
@ -72,10 +72,10 @@
|
|||
- (void)test04PrefetchWithMultipleArrayDifferentQueueWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetch with multiple array at different queue failed"];
|
||||
|
||||
NSArray *imageURLs1 = @[@"http://via.placeholder.com/20x20.jpg",
|
||||
@"http://via.placeholder.com/30x30.jpg"];
|
||||
NSArray *imageURLs2 = @[@"http://via.placeholder.com/30x30.jpg",
|
||||
@"http://via.placeholder.com/40x40.jpg"];
|
||||
NSArray *imageURLs1 = @[@"https://via.placeholder.com/20x20.jpg",
|
||||
@"https://via.placeholder.com/30x30.jpg"];
|
||||
NSArray *imageURLs2 = @[@"https://via.placeholder.com/30x30.jpg",
|
||||
@"https://via.placeholder.com/40x40.jpg"];
|
||||
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||
__block int numberOfPrefetched1 = 0;
|
||||
|
@ -120,7 +120,7 @@
|
|||
// This test also test large URLs and thread-safe problem. You can tested with 2000 urls and get the correct result locally. However, due to the limit of CI, 20 is enough.
|
||||
NSMutableArray<NSURL *> *imageURLs = [NSMutableArray arrayWithCapacity:20];
|
||||
for (size_t i = 1; i <= 20; i++) {
|
||||
NSString *url = [NSString stringWithFormat:@"http://via.placeholder.com/%zux%zu.jpg", i, i];
|
||||
NSString *url = [NSString stringWithFormat:@"https://via.placeholder.com/%zux%zu.jpg", i, i];
|
||||
[imageURLs addObject:[NSURL URLWithString:url]];
|
||||
}
|
||||
self.prefetcher = [SDWebImagePrefetcher new];
|
||||
|
@ -141,9 +141,9 @@
|
|||
}
|
||||
|
||||
- (void)test06PrefetchCancelToken {
|
||||
NSArray *imageURLs = @[@"http://via.placeholder.com/20x20.jpg",
|
||||
@"http://via.placeholder.com/30x30.jpg",
|
||||
@"http://via.placeholder.com/40x40.jpg"];
|
||||
NSArray *imageURLs = @[@"https://via.placeholder.com/20x20.jpg",
|
||||
@"https://via.placeholder.com/30x30.jpg",
|
||||
@"https://via.placeholder.com/40x40.jpg"];
|
||||
SDWebImagePrefetcher *prefetcher = [[SDWebImagePrefetcher alloc] init];
|
||||
SDWebImagePrefetchToken *token = [prefetcher prefetchURLs:imageURLs];
|
||||
expect(prefetcher.runningTokens.count).equal(1);
|
||||
|
@ -154,9 +154,9 @@
|
|||
- (void)test07DownloaderCancelDuringPrefetching {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Downloader cancel during prefetch should not hung up"];
|
||||
|
||||
NSArray *imageURLs = @[@"http://via.placeholder.com/5000x5000.jpg",
|
||||
@"http://via.placeholder.com/6000x6000.jpg",
|
||||
@"http://via.placeholder.com/7000x7000.jpg"];
|
||||
NSArray *imageURLs = @[@"https://via.placeholder.com/5000x5000.jpg",
|
||||
@"https://via.placeholder.com/6000x6000.jpg",
|
||||
@"https://via.placeholder.com/7000x7000.jpg"];
|
||||
for (NSString *url in imageURLs) {
|
||||
[SDImageCache.sharedImageCache removeImageFromDiskForKey:url];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue