Use a weak pointerArray to store the operations for sd_setAnimationImagesWithURLs, avoid extra retain of operation instance

This commit is contained in:
DreamPiggy 2017-12-17 03:04:59 +08:00
parent 958a349c6c
commit 37f84ce6a6
3 changed files with 43 additions and 21 deletions

View File

@ -73,7 +73,7 @@
[self sd_cancelCurrentAnimationImagesLoad]; [self sd_cancelCurrentAnimationImagesLoad];
__weak __typeof(self)wself = self; __weak __typeof(self)wself = self;
NSMutableArray<id<SDWebImageOperation>> *operationsArray = [[NSMutableArray alloc] init]; NSPointerArray *operationsArray = [self sd_animationOperationArray];
[arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) { [arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) {
id <SDWebImageOperation> operation = [[SDWebImageManager sharedManager] loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { id <SDWebImageOperation> operation = [[SDWebImageManager sharedManager] loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
@ -103,14 +103,42 @@
[sself startAnimating]; [sself startAnimating];
}); });
}]; }];
[operationsArray addObject:operation]; @synchronized (self) {
[operationsArray addPointer:(__bridge void *)(operation)];
}
}]; }];
}
[self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"]; static char animationloadOperationKey;
// element is weak because operation instance is retained by SDWebImageManager's runningOperations property
// we should use lock to keep thread-safe because these method may not be acessed from main queue
- (NSPointerArray *)sd_animationOperationArray {
@synchronized(self) {
NSPointerArray *operationsArray = objc_getAssociatedObject(self, &animationloadOperationKey);
if (operationsArray) {
return operationsArray;
}
operationsArray = [NSPointerArray weakObjectsPointerArray];
objc_setAssociatedObject(self, &animationloadOperationKey, operationsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operationsArray;
}
} }
- (void)sd_cancelCurrentAnimationImagesLoad { - (void)sd_cancelCurrentAnimationImagesLoad {
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"]; NSPointerArray *operationsArray = [self sd_animationOperationArray];
if (operationsArray) {
@synchronized (self) {
for (id operation in operationsArray) {
if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
[operation cancel];
}
}
for (size_t i = 0; i < operationsArray.count; i++) {
[operationsArray removePointerAtIndex:i];
}
}
}
} }
#endif #endif

View File

@ -20,7 +20,7 @@
* @param operation the operation * @param operation the operation
* @param key key for storing the operation * @param key key for storing the operation
*/ */
- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key; - (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key;
/** /**
* Cancel all operations for the current UIView and key * Cancel all operations for the current UIView and key

View File

@ -20,7 +20,7 @@ typedef NSMapTable<NSString *, id> SDOperationsDictionary;
@implementation UIView (WebCacheOperation) @implementation UIView (WebCacheOperation)
- (SDOperationsDictionary *)operationDictionary { - (SDOperationsDictionary *)sd_operationDictionary {
@synchronized(self) { @synchronized(self) {
SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
if (operations) { if (operations) {
@ -32,11 +32,11 @@ typedef NSMapTable<NSString *, id> SDOperationsDictionary;
} }
} }
- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key { - (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key {
if (key) { if (key) {
[self sd_cancelImageLoadOperationWithKey:key]; [self sd_cancelImageLoadOperationWithKey:key];
if (operation) { if (operation) {
SDOperationsDictionary *operationDictionary = [self operationDictionary]; SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
@synchronized (self) { @synchronized (self) {
[operationDictionary setObject:operation forKey:key]; [operationDictionary setObject:operation forKey:key];
} }
@ -46,20 +46,14 @@ typedef NSMapTable<NSString *, id> SDOperationsDictionary;
- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key { - (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
// Cancel in progress downloader from queue // Cancel in progress downloader from queue
SDOperationsDictionary *operationDictionary = [self operationDictionary]; SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
id operations; id operation;
@synchronized (self) { @synchronized (self) {
operations = [operationDictionary objectForKey:key]; operation = [operationDictionary objectForKey:key];
} }
if (operations) { if (operation) {
if ([operations isKindOfClass:[NSArray class]]) { if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]){
for (id <SDWebImageOperation> operation in operations) { [(id<SDWebImageOperation>) operation cancel];
if (operation) {
[operation cancel];
}
}
} else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
[(id<SDWebImageOperation>) operations cancel];
} }
@synchronized (self) { @synchronized (self) {
[operationDictionary removeObjectForKey:key]; [operationDictionary removeObjectForKey:key];
@ -69,7 +63,7 @@ typedef NSMapTable<NSString *, id> SDOperationsDictionary;
- (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key { - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key {
if (key) { if (key) {
SDOperationsDictionary *operationDictionary = [self operationDictionary]; SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
@synchronized (self) { @synchronized (self) {
[operationDictionary removeObjectForKey:key]; [operationDictionary removeObjectForKey:key];
} }