diff --git a/packages/react-native/Libraries/Image/RCTUIImageViewAnimated.mm b/packages/react-native/Libraries/Image/RCTUIImageViewAnimated.mm index b2247c58d05..62131f50acb 100644 --- a/packages/react-native/Libraries/Image/RCTUIImageViewAnimated.mm +++ b/packages/react-native/Libraries/Image/RCTUIImageViewAnimated.mm @@ -121,6 +121,8 @@ static NSUInteger RCTDeviceFreeMemory(void) // Calculate max buffer size [self calculateMaxBufferCount]; + [self prefetchNextFrame:nil fetchFrameIndex:1]; + if ([self paused]) { [self start]; } @@ -167,6 +169,21 @@ static NSUInteger RCTDeviceFreeMemory(void) return _displayLink; } +- (void)prefetchNextFrame:(UIImage *)fetchFrame fetchFrameIndex:(NSInteger)fetchFrameIndex +{ + if (!fetchFrame && !(self.frameBuffer.count == self.totalFrameCount) && self.fetchQueue.operationCount == 0) { + // Prefetch next frame in background queue + UIImage *animatedImage = self.animatedImage; + NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; + dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER); + self.frameBuffer[@(fetchFrameIndex)] = frame; + dispatch_semaphore_signal(self.lock); + }]; + [self.fetchQueue addOperation:operation]; + } +} + #pragma mark - Animation - (void)start @@ -210,6 +227,9 @@ static NSUInteger RCTDeviceFreeMemory(void) // Do not skip frame self.currentTime = nextDuration; } + currentFrameIndex = nextFrameIndex; + self.currentFrameIndex = nextFrameIndex; + nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount; } // Update the current frame @@ -219,20 +239,14 @@ static NSUInteger RCTDeviceFreeMemory(void) currentFrame = self.frameBuffer[@(currentFrameIndex)]; fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil; dispatch_semaphore_signal(self.lock); - BOOL bufferFull = NO; if (currentFrame) { dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER); // Remove the frame buffer if need if (self.frameBuffer.count > self.maxBufferCount) { self.frameBuffer[@(currentFrameIndex)] = nil; } - // Check whether we can stop fetch - if (self.frameBuffer.count == totalFrameCount) { - bufferFull = YES; - } dispatch_semaphore_signal(self.lock); self.currentFrame = currentFrame; - self.currentFrameIndex = nextFrameIndex; self.bufferMiss = NO; [self.layer setNeedsDisplay]; } else { @@ -261,17 +275,7 @@ static NSUInteger RCTDeviceFreeMemory(void) fetchFrameIndex = nextFrameIndex; } - if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) { - // Prefetch next frame in background queue - UIImage *animatedImage = self.animatedImage; - NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ - UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; - dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER); - self.frameBuffer[@(fetchFrameIndex)] = frame; - dispatch_semaphore_signal(self.lock); - }]; - [self.fetchQueue addOperation:operation]; - } + [self prefetchNextFrame:fetchFrame fetchFrameIndex:fetchFrameIndex]; } #pragma mark - CALayerDelegate