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;
}
__weak __block NSBlockOperation *weakOp;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// Get mime type
@ -48,7 +49,7 @@ RCT_EXPORT_MODULE()
expectedContentLength:-1
textEncodingName:nil];
[delegate URLRequest:op didReceiveResponse:response];
[delegate URLRequest:weakOp didReceiveResponse:response];
// Load data
NSError *error;
@ -56,11 +57,12 @@ RCT_EXPORT_MODULE()
options:NSDataReadingMappedIfSafe
error:&error];
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];
return op;
}

View File

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

View File

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