Repository navigation
Conversation
…tem image cache Bundled images are loaded with +[UIImage imageNamed:], whose system cache keeps every image ever shown, even after it is unmounted and across memory warnings. When the image source sets cache: 'reload', the bundle asset loaders now read the file directly instead. Default behavior is unchanged. Fixes react#12220
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Fixes #12220.
Bundled images (
require('./photo.jpg')) are loaded on iOS through+[UIImage imageNamed:]. UIKit keeps every image loaded that way in its own cache: after the<Image>changes source or unmounts, the decoded bitmap stays in memory. Slideshows, onboarding flows or image sequences with many large local images grow until the app is killed.Reproduced on 0.88.0 (Release, iOS 27.1 simulator): 20 local 3000x4000 JPEGs shown one after another, then the
<Image>unmounted.cache: 'reload'(this PR)Two simulated memory warnings while the 935 MB were held freed nothing (the app logged
Received memory warning), so this isn't a cache that empties itself under pressure.RN's own
RCTImageCachecan't replace the system cache here: the bundle asset loaders opt out of it (shouldCacheLoadedImagesreturns NO), and it only stores images decoded from data. So simply droppingimageNamed:for everyone would leave small bundled icons uncached. Following the discussion in the issue (no heuristics, let the developer choose per source), this PR makes the existingcache: 'reload'option ("no existing cache data should be used") apply to bundled images too:RCTImageURLLoadergets an optionalloadImageIgnoringCacheForURL:…method.RCTImageLoadercalls it when the request's cache policy isNSURLRequestReloadIgnoringLocalCacheDataand the loader implements it; otherwise nothing changes.RCTBundleAssetImageLoaderandRCTLocalAssetImageLoaderimplement it with the newRCTImageFromLocalAssetURLIgnoringSystemCache, which reads the file withimageWithContentsOfFile:instead ofimageNamed:(the existing file-system fallback). Images compiled into an asset catalog can only be loaded by name and still go through the system cache.Usage:
Changelog:
[IOS] [FIXED] - Bundled images with
cache: 'reload'are no longer kept in the system image cache after they stop being shownTest Plan:
Test app: RN 0.88.0, Release build, iOS 27.1 simulator, patched React Native built from source. 20 local 3000x4000 JPEGs, each shown for 1 s, then the
<Image>unmounted; app footprint sampled every second withfootprint.cache: identical to before the change (grows to 935 MB, stays after unmount).cache: 'reload': 60–110 MB while cycling, 17 MB after unmount.