react-native: Image prefetch does not work on iOS

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

  • Using image prefetch does not work at all on iOS.
  • Preloading the images and then checking Image.queryCache shows an empty query cache
  • Attempting to display images that have been prefetched using cache: 'only-if-cached' will result in no image shown
  • Works absolutely fine on Android
  • There are a number of other issues reporting the same thing in the past this one and another
  • https://www.npmjs.com/package/react-native-fast-image provides the same behaviour so perhaps this isn’t getting much traction but I’m keen to not add on libraries for something that is supposed to be supported

React Native version:

System: OS: macOS 10.15.3 CPU: (4) x64 Intel® Core™ i7-7660U CPU @ 2.50GHz Memory: 289.63 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 10.16.3 - /usr/local/opt/node@10/bin/node Yarn: 1.15.2 - ~/.yarn/bin/yarn npm: 6.9.0 - /usr/local/opt/node@10/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.9.1 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1 Android SDK: API Levels: 28 Build Tools: 28.0.3 System Images: android-29 | Google Play Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: 3.3 AI-182.5107.16.33.5199772 Xcode: 11.3/11C29 - /usr/bin/xcodebuild Languages: Java: 1.8.0_192 - /usr/bin/javac Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: 16.11.0 => 16.11.0 react-native: 0.62.1 => 0.62.1 npmGlobalPackages: react-native: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Preload an image using Image.prefetch(img)
  2. display the image using only-if-cached

OR

  1. Preload an image using Image.prefetch(img)
  2. display the image

Expected Results

Scenario 1

  1. Image is shown

Scenario 1

  1. Image is instantly shown

Snack, code example, screenshot, or link to a repository:

https://snack.expo.io/yseyl0_9N

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 27
  • Comments: 24

Most upvoted comments

I found the cause of this issue.

  1. prefetch method will call imageLoader’s loadImageWithURLRequest method.
  2. This method will set size to CGSizeZero and scale to 1 by default.
  3. Image cache will use url string, size and scale to create a key for storage.
  4. When you set Image’s source, size is image’s size, scale is screen’s scale. So it will never hit the cache.
RCT_EXPORT_METHOD(prefetchImage:(NSURLRequest *)request
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  if (!request) {
    reject(@"E_INVALID_URI", @"Cannot prefetch an image for an empty URI", nil);
    return;
  }
    id<RCTImageLoaderProtocol> imageLoader = (id<RCTImageLoaderProtocol>)[self.bridge
                                                                          moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES];
    [imageLoader loadImageWithURLRequest:request
                                priority:RCTImageLoaderPriorityPrefetch
                                callback:^(NSError *error, UIImage *image) {
        if (error) {
            reject(@"E_PREFETCH_FAILURE", nil, error);
            return;
        }
        resolve(@YES);
    }];
}

- (nullable RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
                                                           priority:(RCTImageLoaderPriority)priority
                                                           callback:(RCTImageLoaderCompletionBlock)callback {
    return [self loadImageWithURLRequest:imageURLRequest
                                    size:CGSizeZero
                                   scale:1
                                 clipped:YES
                              resizeMode:RCTResizeModeStretch
                                priority:priority
                           progressBlock:nil
                        partialLoadBlock:nil
                         completionBlock:callback];
}

It’s 2021, still issue here

Can confirm this on RN 0.61.4! Interesting discovery: the Image.queryCache does show images which are smaller in size…

Measured behavior: Loading large images (eg. Unsplash wallpapers ~1.3MB): no file stored in the fsCachedData folder Loading normal size images (~200KB): file stored in fsCachedData & appears in Image.queryCache

Any movement on this? I’m using Expo and most, if not all of the other options require a bare project to work.

same here it take sometimes for image to load up even queryCache show that image are already cache