Fix retain cyles in RCTNetworkTask when used with RCTFileRequestHandler and RCTDataRequestHandler

Summary: Hi,

While implementing my own `RCTURLRequestHandler` I came across retain cycles in `RCTNetworkTask` when used with `RCTFileRequestHandler` and `RCTDataRequestHandler`.

The `NSBlockOperation` used in `RCTFileRequestHandler` and `RCTDataRequestHandler` could never be dealloc'ed because of a retain cycle.
And then the second issue was that those blocks were also strongly capturing the passed delegate which in this case is the `RCTNetworkTask` itself and then since the task was storing the block as a `requestToken`, the task could never be dealloc'ed as well.

Here are my proposed fixes. Let me know what you think.
Closes https://github.com/facebook/react-native/pull/3884

Reviewed By: svcscm

Differential Revision: D2615353

Pulled By: nicklockwood

fb-gh-sync-id: a73cbecffbebea75aaeb23d39f04a0d87602926f
This commit is contained in:
Jean Regisser 2015-11-04 07:14:34 -08:00 committed by facebook-github-bot-5
parent d799558db5
commit 1e52ef23e7
3 changed files with 12 additions and 8 deletions

View File

@ -36,6 +36,7 @@ RCT_EXPORT_MODULE()
_queue.maxConcurrentOperationCount = 2; _queue.maxConcurrentOperationCount = 2;
} }
__weak __block NSBlockOperation *weakOp;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// Get mime type // Get mime type
@ -48,7 +49,7 @@ RCT_EXPORT_MODULE()
expectedContentLength:-1 expectedContentLength:-1
textEncodingName:nil]; textEncodingName:nil];
[delegate URLRequest:op didReceiveResponse:response]; [delegate URLRequest:weakOp didReceiveResponse:response];
// Load data // Load data
NSError *error; NSError *error;
@ -56,11 +57,12 @@ RCT_EXPORT_MODULE()
options:NSDataReadingMappedIfSafe options:NSDataReadingMappedIfSafe
error:&error]; error:&error];
if (data) { if (data) {
[delegate URLRequest:op didReceiveData:data]; [delegate URLRequest:weakOp didReceiveData:data];
} }
[delegate URLRequest:op didCompleteWithError:error]; [delegate URLRequest:weakOp didCompleteWithError:error];
}]; }];
weakOp = op;
[_queue addOperation:op]; [_queue addOperation:op];
return op; return op;
} }

View File

@ -42,6 +42,7 @@ RCT_EXPORT_MODULE()
_fileQueue.maxConcurrentOperationCount = 4; _fileQueue.maxConcurrentOperationCount = 4;
} }
__weak __block NSBlockOperation *weakOp;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// Get content length // Get content length
@ -49,7 +50,7 @@ RCT_EXPORT_MODULE()
NSFileManager *fileManager = [NSFileManager new]; NSFileManager *fileManager = [NSFileManager new];
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:request.URL.path error:&error]; NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:request.URL.path error:&error];
if (error) { if (error) {
[delegate URLRequest:op didCompleteWithError:error]; [delegate URLRequest:weakOp didCompleteWithError:error];
return; return;
} }
@ -66,18 +67,19 @@ RCT_EXPORT_MODULE()
expectedContentLength:[fileAttributes[NSFileSize] ?: @-1 integerValue] expectedContentLength:[fileAttributes[NSFileSize] ?: @-1 integerValue]
textEncodingName:nil]; textEncodingName:nil];
[delegate URLRequest:op didReceiveResponse:response]; [delegate URLRequest:weakOp didReceiveResponse:response];
// Load data // Load data
NSData *data = [NSData dataWithContentsOfURL:request.URL NSData *data = [NSData dataWithContentsOfURL:request.URL
options:NSDataReadingMappedIfSafe options:NSDataReadingMappedIfSafe
error:&error]; error:&error];
if (data) { if (data) {
[delegate URLRequest:op didReceiveData:data]; [delegate URLRequest:weakOp didReceiveData:data];
} }
[delegate URLRequest:op didCompleteWithError:error]; [delegate URLRequest:weakOp didCompleteWithError:error];
}]; }];
weakOp = op;
[_fileQueue addOperation:op]; [_fileQueue addOperation:op];
return op; return op;
} }

View File

@ -22,7 +22,7 @@ typedef void (^RCTURLRequestResponseBlock)(NSURLResponse *response);
@property (nonatomic, readonly) NSURLRequest *request; @property (nonatomic, readonly) NSURLRequest *request;
@property (nonatomic, readonly) NSNumber *requestID; @property (nonatomic, readonly) NSNumber *requestID;
@property (nonatomic, readonly) id requestToken; @property (nonatomic, readonly, weak) id requestToken;
@property (nonatomic, readonly) NSURLResponse *response; @property (nonatomic, readonly) NSURLResponse *response;
@property (nonatomic, readonly) RCTURLRequestCompletionBlock completionBlock; @property (nonatomic, readonly) RCTURLRequestCompletionBlock completionBlock;