From 6aea50d6f83019f68455edd00f4af00172a3d224 Mon Sep 17 00:00:00 2001 From: Tadeu Zagallo Date: Thu, 11 Jun 2015 10:43:29 -0700 Subject: [PATCH] [ReactNative] Fix racing condition on RCTDataManager --- Libraries/Network/RCTDataManager.m | 78 ++++++++++++++++++------------ 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/Libraries/Network/RCTDataManager.m b/Libraries/Network/RCTDataManager.m index 875d99f31..05a51c169 100644 --- a/Libraries/Network/RCTDataManager.m +++ b/Libraries/Network/RCTDataManager.m @@ -202,6 +202,7 @@ typedef void (^RCTDataLoaderCallback)(NSData *data, NSString *MIMEType, NSError { NSInteger _currentRequestID; NSMapTable *_activeRequests; + dispatch_queue_t _methodQueue; } @synthesize bridge = _bridge; @@ -212,6 +213,7 @@ RCT_EXPORT_MODULE() { if ((self = [super init])) { _currentRequestID = 0; + _methodQueue = dispatch_queue_create("com.facebook.React.RCTDataManager", DISPATCH_QUEUE_SERIAL); _activeRequests = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:0]; @@ -219,6 +221,11 @@ RCT_EXPORT_MODULE() return self; } +- (dispatch_queue_t)methodQueue +{ + return _methodQueue; +} + - (void)buildRequest:(NSDictionary *)query responseSender:(RCTResponseSenderBlock)responseSender { @@ -381,55 +388,62 @@ RCT_EXPORT_MODULE() - (void)URLRequest:(id)requestToken didReceiveResponse:(NSURLResponse *)response { - RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; - RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); + dispatch_async(_methodQueue, ^{ + RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; + RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); - request.response = response; + request.response = response; - NSHTTPURLResponse *httpResponse = nil; - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - // Might be a local file request - httpResponse = (NSHTTPURLResponse *)response; - } + NSHTTPURLResponse *httpResponse = nil; + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + // Might be a local file request + httpResponse = (NSHTTPURLResponse *)response; + } - NSArray *responseJSON = @[request.requestID, - @(httpResponse.statusCode ?: 200), - httpResponse.allHeaderFields ?: @{}, - ]; + NSArray *responseJSON = @[request.requestID, + @(httpResponse.statusCode ?: 200), + httpResponse.allHeaderFields ?: @{}, + ]; - [_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse" - body:responseJSON]; + [_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse" + body:responseJSON]; + }); } - (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data { - RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; - RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); + dispatch_async(_methodQueue, ^{ + RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; + RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); - if (request.incrementalUpdates) { - [self sendData:data forRequestToken:requestToken]; - } else { - [request.data appendData:data]; - } + if (request.incrementalUpdates) { + [self sendData:data forRequestToken:requestToken]; + } else { + [request.data appendData:data]; + } + }); } - (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error { - RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; - RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); + dispatch_async(_methodQueue, ^{ + RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken]; + RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken); - if (!request.incrementalUpdates) { - [self sendData:request.data forRequestToken:requestToken]; - } + if (!request.incrementalUpdates) { + [self sendData:request.data forRequestToken:requestToken]; + } - NSArray *responseJSON = @[request.requestID, - error.localizedDescription ?: [NSNull null] - ]; + NSArray *responseJSON = @[ + request.requestID, + error.localizedDescription ?: [NSNull null], + ]; - [_bridge.eventDispatcher sendDeviceEventWithName:@"didCompleteNetworkResponse" - body:responseJSON]; + [_bridge.eventDispatcher sendDeviceEventWithName:@"didCompleteNetworkResponse" + body:responseJSON]; - [_activeRequests removeObjectForKey:requestToken]; + [_activeRequests removeObjectForKey:requestToken]; + }); } #pragma mark - JS API