Merge pull request #3592 from dreampiggy/feature/avoid_cancel_image_options

Added `SDWebImageAvoidAutoCancelImage` to avoid cancel loading image requests for the same operation key
This commit is contained in:
DreamPiggy 2023-09-02 19:26:10 +08:00 committed by GitHub
commit 2db2c7ad5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 4 deletions

View File

@ -107,6 +107,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* of the placeholder image until after the image has finished loading.
* @note This is used to treate placeholder as an **Error Placeholder** but not **Loading Placeholder** by defaults. if the image loading is cancelled or error, the placeholder will be always set.
* @note Therefore, if you want both **Error Placeholder** and **Loading Placeholder** exist, use `SDWebImageAvoidAutoSetImage` to manually set the two placeholders and final loaded image by your hand depends on loading result.
* @note This options is UI level options, has no usage on ImageManager or other components.
*/
SDWebImageDelayPlaceholder = 1 << 8,
@ -120,6 +121,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* By default, image is added to the imageView after download. But in some cases, we want to
* have the hand before setting the image (apply a filter or add it with cross-fade animation for instance)
* Use this flag if you want to manually set the image in the completion when success
* @note This options is UI level options, has no usage on ImageManager or other components.
*/
SDWebImageAvoidAutoSetImage = 1 << 10,
@ -165,6 +167,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image when the callback from manager is asynchronous (from network, or disk cache query)
* This mask can force to apply view transition for any cases, like memory cache query, or sync disk cache query.
* @note This options is UI level options, has no usage on ImageManager or other components.
*/
SDWebImageForceTransition = 1 << 17,
@ -206,7 +209,15 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* We usually don't apply transform on vector images, because vector images supports dynamically changing to any size, rasterize to a fixed size will loss details. To modify vector images, you can process the vector data at runtime (such as modifying PDF tag / SVG element).
* Use this flag to transform them anyway.
*/
SDWebImageTransformVectorImage = 1 << 23
SDWebImageTransformVectorImage = 1 << 23,
/**
* By defaults, when you use UI-level category like `sd_setImageWithURL:` on UIImageView, it will cancel the loading image requests.
* However, some users may choose to not cancel the loading image requests and always start new pipeline.
* Use this flag to disable automatic cancel behavior.
* @note This options is UI level options, has no usage on ImageManager or other components.
*/
SDWebImageAvoidAutoCancelImage = 1 << 24,
};

View File

@ -76,7 +76,10 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
context = [mutableContext copy];
}
self.sd_latestOperationKey = validOperationKey;
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
if (!(SD_OPTIONS_CONTAINS(options, SDWebImageAvoidAutoCancelImage))) {
// cancel previous loading for the same set-image operation key by default
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
}
SDWebImageLoadState *loadState = [self sd_imageLoadStateForKey:validOperationKey];
if (!loadState) {
loadState = [SDWebImageLoadState new];

View File

@ -40,7 +40,6 @@ typedef NSMapTable<NSString *, id<SDWebImageOperation>> SDOperationsDictionary;
- (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key {
if (key) {
[self sd_cancelImageLoadOperationWithKey:key];
if (operation) {
SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
@synchronized (self) {

View File

@ -306,13 +306,38 @@
[self waitForExpectationsWithCommonTimeout];
}
- (void)testUIViewAutoCancelImage {
UIView *imageView = [[UIView alloc] init];
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
SDWebImageCombinedOperation *op1 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
SDWebImageCombinedOperation *op2 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
// op1 should be automatically cancelled
expect(op1.isCancelled).beTruthy();
expect(op2.isCancelled).beFalsy();
}
- (void)testUIViewAvoidAutoCancelImage {
UIView *imageView = [[UIView alloc] init];
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
SDWebImageCombinedOperation *op1 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
SDWebImageCombinedOperation *op2 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:SDWebImageAvoidAutoCancelImage context:nil setImageBlock:nil progress:nil completed:nil];
// opt1 should not be automatically cancelled
expect(op1.isCancelled).beFalsy();
expect(op2.isCancelled).beFalsy();
}
- (void)testUIViewCancelCurrentImageLoad {
UIView *imageView = [[UIView alloc] init];
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
SDWebImageCombinedOperation *op1 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
[imageView sd_cancelCurrentImageLoad];
expect(op1.isCancelled).beTruthy();
NSString *operationKey = NSStringFromClass(UIView.class);
expect([imageView sd_imageLoadOperationForKey:operationKey]).beNil();
}