Cleanup RCTImageLoader weakSelf/strongSelf
Reviewed By: mmmulani Differential Revision: D3542393 fbshipit-source-id: b241586b0da254f688d0e8bdbf7d4ce72dc0d21f
This commit is contained in:
parent
3816ced49b
commit
ff3ab32a72
|
@ -13,11 +13,9 @@
|
||||||
#import "RCTURLRequestHandler.h"
|
#import "RCTURLRequestHandler.h"
|
||||||
#import "RCTResizeMode.h"
|
#import "RCTResizeMode.h"
|
||||||
|
|
||||||
@class ALAssetsLibrary;
|
|
||||||
|
|
||||||
typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total);
|
typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total);
|
||||||
typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image);
|
typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image);
|
||||||
typedef void (^RCTImageLoaderCancellationBlock)(void);
|
typedef dispatch_block_t RCTImageLoaderCancellationBlock;
|
||||||
|
|
||||||
@interface UIImage (React)
|
@interface UIImage (React)
|
||||||
|
|
||||||
|
|
|
@ -293,12 +293,11 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
completionBlock:(void (^)(NSError *error, id imageOrData))completionBlock
|
completionBlock:(void (^)(NSError *error, id imageOrData))completionBlock
|
||||||
{
|
{
|
||||||
__block volatile uint32_t cancelled = 0;
|
__block volatile uint32_t cancelled = 0;
|
||||||
__block void(^cancelLoad)(void) = nil;
|
__block dispatch_block_t cancelLoad = nil;
|
||||||
__weak RCTImageLoader *weakSelf = self;
|
__weak RCTImageLoader *weakSelf = self;
|
||||||
|
|
||||||
void (^completionHandler)(NSError *error, id imageOrData) = ^(NSError *error, id imageOrData) {
|
void (^completionHandler)(NSError *error, id imageOrData) = ^(NSError *error, id imageOrData) {
|
||||||
if (RCTIsMainQueue()) {
|
if (RCTIsMainQueue()) {
|
||||||
|
|
||||||
// Most loaders do not return on the main thread, so caller is probably not
|
// Most loaders do not return on the main thread, so caller is probably not
|
||||||
// expecting it, and may do expensive post-processing in the callback
|
// expecting it, and may do expensive post-processing in the callback
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
@ -315,21 +314,24 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
if (!_URLCacheQueue) {
|
if (!_URLCacheQueue) {
|
||||||
[self setUp];
|
[self setUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(_URLCacheQueue, ^{
|
dispatch_async(_URLCacheQueue, ^{
|
||||||
|
__typeof(self) strongSelf = weakSelf;
|
||||||
if (!self->_URLCache) {
|
|
||||||
self->_URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
|
|
||||||
diskCapacity:200 * 1024 * 1024 // 200MB
|
|
||||||
diskPath:@"React/RCTImageDownloader"];
|
|
||||||
}
|
|
||||||
|
|
||||||
RCTImageLoader *strongSelf = weakSelf;
|
|
||||||
if (cancelled || !strongSelf) {
|
if (cancelled || !strongSelf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use a local variable so we can reassign it in this block
|
||||||
|
NSURLRequest *request = imageURLRequest;
|
||||||
|
|
||||||
|
// Add missing png extension
|
||||||
|
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
||||||
|
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||||||
|
mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
|
||||||
|
request = mutableRequest;
|
||||||
|
}
|
||||||
|
|
||||||
// Find suitable image URL loader
|
// Find suitable image URL loader
|
||||||
NSURLRequest *request = imageURLRequest; // Use a local variable so we can reassign it in this block
|
|
||||||
id<RCTImageURLLoader> loadHandler = [strongSelf imageURLLoaderForURL:request.URL];
|
id<RCTImageURLLoader> loadHandler = [strongSelf imageURLLoaderForURL:request.URL];
|
||||||
if (loadHandler) {
|
if (loadHandler) {
|
||||||
cancelLoad = [loadHandler loadImageForURL:request.URL
|
cancelLoad = [loadHandler loadImageForURL:request.URL
|
||||||
|
@ -338,27 +340,44 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
resizeMode:resizeMode
|
resizeMode:resizeMode
|
||||||
progressHandler:progressHandler
|
progressHandler:progressHandler
|
||||||
completionHandler:completionHandler] ?: ^{};
|
completionHandler:completionHandler] ?: ^{};
|
||||||
return;
|
} else {
|
||||||
|
// Use networking module to load image
|
||||||
|
cancelLoad = [strongSelf _loadURLRequest:request
|
||||||
|
progressBlock:progressHandler
|
||||||
|
completionBlock:completionHandler];
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ^{
|
||||||
|
if (cancelLoad) {
|
||||||
|
cancelLoad();
|
||||||
|
}
|
||||||
|
OSAtomicOr32Barrier(1, &cancelled);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
|
||||||
|
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
|
||||||
|
completionBlock:(void (^)(NSError *error, id imageOrData))completionHandler
|
||||||
|
{
|
||||||
// Check if networking module is available
|
// Check if networking module is available
|
||||||
if (RCT_DEBUG && ![self->_bridge respondsToSelector:@selector(networking)]) {
|
if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
|
||||||
RCTLogError(@"No suitable image URL loader found for %@. You may need to "
|
RCTLogError(@"No suitable image URL loader found for %@. You may need to "
|
||||||
" import the RCTNetwork library in order to load images.",
|
" import the RCTNetwork library in order to load images.",
|
||||||
request.URL.absoluteString);
|
request.URL.absoluteString);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCTNetworking *networking = [_bridge networking];
|
||||||
|
|
||||||
// Check if networking module can load image
|
// Check if networking module can load image
|
||||||
if (RCT_DEBUG && ![self->_bridge.networking canHandleRequest:request]) {
|
if (RCT_DEBUG && ![networking canHandleRequest:request]) {
|
||||||
RCTLogError(@"No suitable image URL loader found for %@", request.URL.absoluteString);
|
RCTLogError(@"No suitable image URL loader found for %@", request.URL.absoluteString);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use networking module to load image
|
// Use networking module to load image
|
||||||
RCTURLRequestCompletionBlock processResponse =
|
RCTURLRequestCompletionBlock processResponse = ^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||||
^(NSURLResponse *response, NSData *data, NSError *error) {
|
|
||||||
|
|
||||||
// Check for system errors
|
// Check for system errors
|
||||||
if (error) {
|
if (error) {
|
||||||
completionHandler(error, nil);
|
completionHandler(error, nil);
|
||||||
|
@ -383,17 +402,15 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
completionHandler(nil, data);
|
completionHandler(nil, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add missing png extension
|
|
||||||
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
|
||||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
|
||||||
mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
|
|
||||||
request = mutableRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for cached response before reloading
|
// Check for cached response before reloading
|
||||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||||
NSCachedURLResponse *cachedResponse = [self->_URLCache cachedResponseForRequest:request];
|
if (!_URLCache) {
|
||||||
|
_URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
|
||||||
|
diskCapacity:200 * 1024 * 1024 // 200MB
|
||||||
|
diskPath:@"React/RCTImageDownloader"];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSCachedURLResponse *cachedResponse = [_URLCache cachedResponseForRequest:request];
|
||||||
while (cachedResponse) {
|
while (cachedResponse) {
|
||||||
if ([cachedResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
|
if ([cachedResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)cachedResponse.response;
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)cachedResponse.response;
|
||||||
|
@ -401,22 +418,23 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
NSString *location = httpResponse.allHeaderFields[@"Location"];
|
NSString *location = httpResponse.allHeaderFields[@"Location"];
|
||||||
if (location == nil) {
|
if (location == nil) {
|
||||||
completionHandler(RCTErrorWithMessage(@"Image redirect without location"), nil);
|
completionHandler(RCTErrorWithMessage(@"Image redirect without location"), nil);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *redirectURL = [NSURL URLWithString: location relativeToURL: request.URL];
|
NSURL *redirectURL = [NSURL URLWithString: location relativeToURL: request.URL];
|
||||||
request = [NSURLRequest requestWithURL:redirectURL];
|
request = [NSURLRequest requestWithURL:redirectURL];
|
||||||
cachedResponse = [self->_URLCache cachedResponseForRequest:request];
|
cachedResponse = [_URLCache cachedResponseForRequest:request];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processResponse(cachedResponse.response, cachedResponse.data, nil);
|
processResponse(cachedResponse.response, cachedResponse.data, nil);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download image
|
// Download image
|
||||||
RCTNetworkTask *task = [self->_bridge.networking networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
|
__weak __typeof(self) weakSelf = self;
|
||||||
|
RCTNetworkTask *task = [networking networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
completionHandler(error, nil);
|
completionHandler(error, nil);
|
||||||
[weakSelf dequeueTasks];
|
[weakSelf dequeueTasks];
|
||||||
|
@ -424,6 +442,10 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(self->_URLCacheQueue, ^{
|
dispatch_async(self->_URLCacheQueue, ^{
|
||||||
|
__typeof(self) strongSelf = self;
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the response
|
// Cache the response
|
||||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||||
|
@ -438,33 +460,24 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
processResponse(response, data, nil);
|
processResponse(response, data, nil);
|
||||||
|
|
||||||
// Prepare for next task
|
// Prepare for next task
|
||||||
[weakSelf dequeueTasks];
|
[strongSelf dequeueTasks];
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
task.downloadProgressBlock = progressHandler;
|
task.downloadProgressBlock = progressHandler;
|
||||||
|
|
||||||
if (!self->_pendingTasks) {
|
|
||||||
self->_pendingTasks = [NSMutableArray new];
|
|
||||||
}
|
|
||||||
if (task) {
|
if (task) {
|
||||||
[self->_pendingTasks addObject:task];
|
if (!_pendingTasks) {
|
||||||
[weakSelf dequeueTasks];
|
_pendingTasks = [NSMutableArray new];
|
||||||
|
}
|
||||||
|
[_pendingTasks addObject:task];
|
||||||
|
[self dequeueTasks];
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelLoad = ^{
|
|
||||||
[task cancel];
|
|
||||||
[weakSelf dequeueTasks];
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return ^{
|
return ^{
|
||||||
if (cancelLoad) {
|
[task cancel];
|
||||||
cancelLoad();
|
[weakSelf dequeueTasks];
|
||||||
}
|
|
||||||
OSAtomicOr32Barrier(1, &cancelled);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue