Cleanup RCTImageLoader weakSelf/strongSelf

Reviewed By: mmmulani

Differential Revision: D3542393

fbshipit-source-id: b241586b0da254f688d0e8bdbf7d4ce72dc0d21f
This commit is contained in:
Pieter De Baets 2016-07-11 13:23:40 -07:00 committed by Facebook Github Bot 8
parent 3816ced49b
commit ff3ab32a72
2 changed files with 150 additions and 139 deletions

View File

@ -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)

View File

@ -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);
}; };
} }