Skip to content

Commit 235749b

Browse files
nicklockwoodFacebook Github Bot 3
authored andcommitted
Fix missing images
Summary: Under rare and as-yet-to-be determined circumstances, images can sometimes fail to load/download and get "stuck", without producing an error. Because the `RCTNetworkTask` for these images is stuck in the "in progress" state, they clog up the RCTImageLoader task queue, which has a limit of 4 concurrent in-progress tasks. This was previously masked by the fact that we automatically cancelled image requests when the RCTImageView moved offscreen, but we no longer do that. This diff adds logic to detect some types of stuck task and remove them, thereby unblocking the queue. I've also restored the functionality of cancelling downloads for offscreen images (but not unloading the image itself) so that stuck images will be cancelled when you move to another screen, instead of using up space in the queue forever. Reviewed By: fkgozali Differential Revision: D3398105 fbshipit-source-id: 75ee40d06a872ae8e1cb57f02f9cad57c459143c
1 parent a05e05f commit 235749b

File tree

4 files changed

+35
-19
lines changed

4 files changed

+35
-19
lines changed

Libraries/Image/RCTImageLoader.m

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ - (void)setUp
6767
// Set defaults
6868
_maxConcurrentLoadingTasks = _maxConcurrentLoadingTasks ?: 4;
6969
_maxConcurrentDecodingTasks = _maxConcurrentDecodingTasks ?: 2;
70-
_maxConcurrentDecodingBytes = _maxConcurrentDecodingBytes ?: 30 * 1024 *1024; // 30MB
70+
_maxConcurrentDecodingBytes = _maxConcurrentDecodingBytes ?: 30 * 1024 * 1024; // 30MB
7171

7272
_URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
7373

@@ -241,8 +241,15 @@ - (void)dequeueTasks
241241
_activeTasks--;
242242
break;
243243
case RCTNetworkTaskPending:
244+
break;
244245
case RCTNetworkTaskInProgress:
245-
// Do nothing
246+
// Check task isn't "stuck"
247+
if (task.requestToken == nil) {
248+
RCTLogWarn(@"Task orphaned for request %@", task.request);
249+
[_pendingTasks removeObject:task];
250+
_activeTasks--;
251+
[task cancel];
252+
}
246253
break;
247254
}
248255
}
@@ -412,6 +419,7 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithURLRequest:(NSURLRequest *
412419
RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
413420
if (error) {
414421
completionHandler(error, nil);
422+
[weakSelf dequeueTasks];
415423
return;
416424
}
417425

@@ -429,7 +437,7 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithURLRequest:(NSURLRequest *
429437
// Process image data
430438
processResponse(response, data, nil);
431439

432-
//clean up
440+
// Prepare for next task
433441
[weakSelf dequeueTasks];
434442

435443
});
@@ -442,10 +450,7 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithURLRequest:(NSURLRequest *
442450
}
443451
if (task) {
444452
[_pendingTasks addObject:task];
445-
if (MAX(_activeTasks, _scheduledDecodes) < _maxConcurrentLoadingTasks) {
446-
[task start];
447-
_activeTasks++;
448-
}
453+
[weakSelf dequeueTasks];
449454
}
450455

451456
cancelLoad = ^{

Libraries/Image/RCTImageView.m

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,13 @@ - (void)didMoveToWindow
315315
{
316316
[super didMoveToWindow];
317317

318-
if (self.window && (!self.image || self.image == _defaultImage)) {
318+
if (!self.window) {
319+
// Cancel loading the image if we've moved offscreen. In addition to helping
320+
// pritoritise image requests that are actually on-screen, this removes
321+
// requests that have gotten "stuck" from the queue, unblocking other images
322+
// from loading.
323+
[self cancelImageLoad];
324+
} else if (!self.image || self.image == _defaultImage) {
319325
[self reloadImage];
320326
}
321327
}

Libraries/Network/RCTFileRequestHandler.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ - (NSOperation *)sendRequest:(NSURLRequest *)request
4949
NSError *error = nil;
5050
NSFileManager *fileManager = [NSFileManager new];
5151
NSDictionary<NSString *, id> *fileAttributes = [fileManager attributesOfItemAtPath:request.URL.path error:&error];
52-
if (error) {
52+
if (!fileAttributes) {
5353
[delegate URLRequest:weakOp didCompleteWithError:error];
5454
return;
5555
}

Libraries/Network/RCTNetworkTask.m

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,35 +63,40 @@ - (void)start
6363

6464
- (void)cancel
6565
{
66+
_status = RCTNetworkTaskFinished;
6667
__strong id strongToken = _requestToken;
6768
if (strongToken && [_handler respondsToSelector:@selector(cancelRequest:)]) {
6869
[_handler cancelRequest:strongToken];
6970
}
7071
[self invalidate];
71-
_status = RCTNetworkTaskFinished;
7272
}
7373

7474
- (BOOL)validateRequestToken:(id)requestToken
7575
{
76+
BOOL valid = YES;
7677
if (_requestToken == nil) {
7778
if (requestToken == nil) {
78-
return NO;
79+
if (RCT_DEBUG) {
80+
RCTLogError(@"Missing request token for request: %@", _request);
81+
}
82+
valid = NO;
7983
}
8084
_requestToken = requestToken;
81-
}
82-
if (![requestToken isEqual:_requestToken]) {
85+
} else if (![requestToken isEqual:_requestToken]) {
8386
if (RCT_DEBUG) {
8487
RCTLogError(@"Unrecognized request token: %@ expected: %@", requestToken, _requestToken);
8588
}
89+
valid = NO;
90+
}
91+
if (!valid) {
92+
_status = RCTNetworkTaskFinished;
8693
if (_completionBlock) {
87-
_completionBlock(_response, _data, [NSError errorWithDomain:RCTErrorDomain code:0
88-
userInfo:@{NSLocalizedDescriptionKey: @"Unrecognized request token."}]);
94+
_completionBlock(_response, nil, [NSError errorWithDomain:RCTErrorDomain code:0
95+
userInfo:@{NSLocalizedDescriptionKey: @"Invalid request token."}]);
8996
}
9097
[self invalidate];
91-
_status = RCTNetworkTaskFinished;
92-
return NO;
9398
}
94-
return YES;
99+
return valid;
95100
}
96101

97102
- (void)URLRequest:(id)requestToken didSendDataWithProgress:(int64_t)bytesSent
@@ -132,11 +137,11 @@ - (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data
132137
- (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error
133138
{
134139
if ([self validateRequestToken:requestToken]) {
140+
_status = RCTNetworkTaskFinished;
135141
if (_completionBlock) {
136142
_completionBlock(_response, _data, error);
137143
}
138144
[self invalidate];
139-
_status = RCTNetworkTaskFinished;
140145
}
141146
}
142147

0 commit comments

Comments
 (0)