Use a copy-weak maptable for operations stored in UIView(WebCacheOperation) category to avoid retain of operation, and also use lock to keep thread-safe

This commit is contained in:
DreamPiggy 2017-12-17 01:26:03 +08:00
parent df7ed34c14
commit 958a349c6c
1 changed files with 23 additions and 10 deletions

View File

@ -14,18 +14,22 @@
static char loadOperationKey;
typedef NSMutableDictionary<NSString *, id> SDOperationsDictionary;
// key is copy, value 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
typedef NSMapTable<NSString *, id> SDOperationsDictionary;
@implementation UIView (WebCacheOperation)
- (SDOperationsDictionary *)operationDictionary {
SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
if (operations) {
@synchronized(self) {
SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
if (operations) {
return operations;
}
operations = [[NSMapTable alloc] initWithKeyOptions:NSMapTableCopyIn valueOptions:NSMapTableWeakMemory capacity:0];
objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operations;
}
operations = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operations;
}
- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key {
@ -33,7 +37,9 @@ typedef NSMutableDictionary<NSString *, id> SDOperationsDictionary;
[self sd_cancelImageLoadOperationWithKey:key];
if (operation) {
SDOperationsDictionary *operationDictionary = [self operationDictionary];
operationDictionary[key] = operation;
@synchronized (self) {
[operationDictionary setObject:operation forKey:key];
}
}
}
}
@ -41,7 +47,10 @@ typedef NSMutableDictionary<NSString *, id> SDOperationsDictionary;
- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
// Cancel in progress downloader from queue
SDOperationsDictionary *operationDictionary = [self operationDictionary];
id operations = operationDictionary[key];
id operations;
@synchronized (self) {
operations = [operationDictionary objectForKey:key];
}
if (operations) {
if ([operations isKindOfClass:[NSArray class]]) {
for (id <SDWebImageOperation> operation in operations) {
@ -52,14 +61,18 @@ typedef NSMutableDictionary<NSString *, id> SDOperationsDictionary;
} else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
[(id<SDWebImageOperation>) operations cancel];
}
[operationDictionary removeObjectForKey:key];
@synchronized (self) {
[operationDictionary removeObjectForKey:key];
}
}
}
- (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key {
if (key) {
SDOperationsDictionary *operationDictionary = [self operationDictionary];
[operationDictionary removeObjectForKey:key];
@synchronized (self) {
[operationDictionary removeObjectForKey:key];
}
}
}