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
|
I'd really have assumed that the UIImage internal image cache responds to memory warnings. Bypassing it just for the sake of showing a smaller memory footprint, while making UX worse is making worse optimization trade-off. Is there external evidence for this? |
|
Fair question. What I have is from the simulator only: with 20 bundled 3000x4000 JPEGs shown one after another and then the That doesn't show the cache won't drain under real memory pressure on a device, which is what actually matters. I'll run the same test on a physical device and report back whether the cache drains or the app gets killed. If it drains, this isn't needed and I'll close it. On the UX side: the default path is unchanged. Bundled images only skip the system cache when the source sets |
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.