Merge pull request #2986 from dreampiggy/feature_pass_set_operation_key

Feature pass the set operation key into context option from upstream. Fix the potential retain cycle if user use custom manager
This commit is contained in:
DreamPiggy 2020-04-26 13:45:04 +08:00 committed by GitHub
commit c4aaa8c63c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 1 deletions

View File

@ -52,10 +52,19 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
context = [context copy]; // copy to avoid mutable object
if (context) {
// copy to avoid mutable object
context = [context copy];
} else {
context = [NSDictionary dictionary];
}
NSString *validOperationKey = context[SDWebImageContextSetImageOperationKey];
if (!validOperationKey) {
// pass through the operation key to downstream, which can used for tracing operation or image view class
validOperationKey = NSStringFromClass([self class]);
SDWebImageMutableContext *mutableContext = [context mutableCopy];
mutableContext[SDWebImageContextSetImageOperationKey] = validOperationKey;
context = [mutableContext copy];
}
self.sd_latestOperationKey = validOperationKey;
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
@ -83,6 +92,11 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
SDWebImageManager *manager = context[SDWebImageContextCustomManager];
if (!manager) {
manager = [SDWebImageManager sharedManager];
} else {
// remove this manager to avoid retain cycle (manger -> loader -> operation -> context -> manager)
SDWebImageMutableContext *mutableContext = [context mutableCopy];
mutableContext[SDWebImageContextCustomManager] = nil;
context = [mutableContext copy];
}
SDImageLoaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {

View File

@ -350,6 +350,32 @@
[self waitForExpectationsWithCommonTimeout];
}
- (void)testUIViewOperationKeyContextWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView operation key context should pass through"];
UIView *view = [[UIView alloc] init];
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
SDWebImageManager *customManager = [[SDWebImageManager alloc] initWithCache:SDImageCachesManager.sharedManager loader:SDImageLoadersManager.sharedManager];
customManager.optionsProcessor = [SDWebImageOptionsProcessor optionsProcessorWithBlock:^SDWebImageOptionsResult * _Nullable(NSURL * _Nullable url, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
// expect manager does not exist, avoid retain cycle
expect(context[SDWebImageContextCustomManager]).beNil();
// expect operation key to be the image view class
expect(context[SDWebImageContextSetImageOperationKey]).equal(NSStringFromClass(view.class));
return [[SDWebImageOptionsResult alloc] initWithOptions:options context:context];
}];
[view sd_internalSetImageWithURL:originalImageURL
placeholderImage:nil
options:0
context:@{SDWebImageContextCustomManager: customManager}
setImageBlock:nil
progress:nil
completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
#pragma mark - Helper
- (UIWindow *)window {
if (!_window) {