探究react-native 源码的图片缓存问题
发布时间 - 2026-01-11 02:56:57 点击率:次本文为xcode模拟器测试,rn版本0.44.3

突然想学习下RN是如何封装ios中的UIImage的,看着看着发现图片的缓存问题是个坑。。。
先看js端图片使用的三种方式,依次排序1、2、3
<Image source={{uri:url}} style={{width:200,height:200}}/> // 1、 加载远程图片
<Image source={{uri:'1.png'}} style={{width:50,height:50}}/> //2、加载xcode中图片
<Image source={require('../../../Resources/Images/Contact/conact_searchIcon@3x.png')}/> //3、加载js中图片
1、2必须设置图片宽高,3不需设置。
对应的ios原生端文件是RCTImageViewManager,暴露的属性
RCT_REMAP_VIEW_PROPERTY(source, imageSources, NSArray<RCTImageSource *>);
就是js中Image组件的属性source,在js中设置source会触发该属性的setter方法。进入RCTImageView的
- (void)setImageSources:(NSArray<RCTImageSource *> *)imageSources
{
if (![imageSources isEqual:_imageSources]) {
_imageSources = [imageSources copy];
[self reloadImage];
}
}
通过此方法中断点打印imageSources,依次得到下面结果:
可见,Image组件加载图片都是采用URL的形式,将图片当作网络资源。不同的是URL的类型:
加载网络上图片 : http:// 加载xcode资源 : file:// 加载js中图片 : http://localhost:8081
追踪setter方法,到RCTImageLoader.m中的如下方法
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
size:(CGSize)size
scale:(CGFloat)scale
clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
{
__block volatile uint32_t cancelled = 0;
__block dispatch_block_t cancelLoad = nil;
dispatch_block_t cancellationBlock = ^{
dispatch_block_t cancelLoadLocal = cancelLoad;
if (cancelLoadLocal && !cancelled) {
cancelLoadLocal();
}
OSAtomicOr32Barrier(1, &cancelled);
};
// 下载图片完成后回调
__weak RCTImageLoader *weakSelf = self;
void (^completionHandler)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
__typeof(self) strongSelf = weakSelf;
if (cancelled || !strongSelf) {
return;
}
// 如果imageOrData是图片类型,则直接回调
// 此处,如果是第二种情况,则会满足,其他情况继续走下面方法
if (!imageOrData || [imageOrData isKindOfClass:[UIImage class]]) {
cancelLoad = nil;
completionBlock(error, imageOrData);
return;
}
// 在内存中查看是否存在该url对应的字节码图片
if (cacheResult) {
UIImage *image = [[strongSelf imageCache] imageForUrl:imageURLRequest.URL.absoluteString
size:size
scale:scale
resizeMode:resizeMode
responseDate:fetchDate];
if (image) {
cancelLoad = nil;
completionBlock(nil, image);
return;
}
}
// 若没有缓存,则将图片解压,再将解压后图片缓存block
RCTImageLoaderCompletionBlock decodeCompletionHandler = ^(NSError *error_, UIImage *image) {
if (cacheResult && image) {
// Store decoded image in cache
[[strongSelf imageCache] addImageToCache:image
URL:imageURLRequest.URL.absoluteString
size:size
scale:scale
resizeMode:resizeMode
responseDate:fetchDate];
}
cancelLoad = nil;
completionBlock(error_, image);
};
// 具体的解压过程
cancelLoad = [strongSelf decodeImageData:imageOrData
size:size
scale:scale
clipped:clipped
resizeMode:resizeMode
completionBlock:decodeCompletionHandler];
};
// 走具体的方法加载图片,1、3种情况用网络请求下载,2情况加载本地文件
cancelLoad = [self _loadImageOrDataWithURLRequest:imageURLRequest
size:size
scale:scale
resizeMode:resizeMode
progressBlock:progressBlock
partialLoadBlock:partialLoadBlock
completionBlock:completionHandler];
return cancellationBlock;
}
具体的缓存类是RCTImageCache,采用NSCache缓存,方法
- (void)addImageToCache:(UIImage *)image
forKey:(NSString *)cacheKey
{
if (!image) {
return;
}
CGFloat bytes = image.size.width * image.size.height * image.scale * image.scale * 4;
if (bytes <= RCTMaxCachableDecodedImageSizeInBytes) {
[self->_decodedImageCache setObject:image
forKey:cacheKey
cost:bytes];
}
}
RCTMaxCachableDecodedImageSizeInBytes是个常量,为1048576,也就是只缓存小于1MB的图片。
问题出在cacheKey,查看缓存key的方法
static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale,
RCTResizeMode resizeMode, NSString *responseDate)
{
return [NSString stringWithFormat:@"%@|%g|%g|%g|%zd|%@",
imageTag, size.width, size.height, scale, resizeMode, responseDate];
}
缓存key的生成方法中包含了responseDate,responseDate是网络请求时返回来的
复制代码 代码如下:
responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
1、3方式每次加载都是一个网络请求,那么网络请求的时间总是变化的,于是responseDate是变化的,cacheKey不唯一,所以虽然系统做了图片的缓存,但是每次取出的都为nil,缓存无效。
2方式加载具体方法在RCTLocalAssetImageLoader.m中,其调用的是RCTUtils的RCTImageFromLocalAssetURL方法
UIImage *__nullable RCTImageFromLocalAssetURL(NSURL *imageURL)
{
// .....省略各种处理
UIImage *image = nil;
if (bundle) {
image = [UIImage imageNamed:imageName inBundle:bundle compatibleWithTraitCollection:nil];
} else {
image = [UIImage imageNamed:imageName];
}
// .....省略各种处理
return image;
}
可见是采用[UIImage imageNamed:imageName]的方式加载xcode自带的图片,这个是有内存缓存的。
综上,对react-native图片加载
1、3情况,没有内存缓存
2情况有系统默认的内存缓存
所有情况都没有磁盘缓存
想让内存缓存生效,只需要改变cacheKey的生成规则即可。
补充:沙盒下面的Library/Caches/项目bunderId号/fsCachedData文件夹里面会磁盘缓存大于一定值(测试约为5kb)的图片和文件,这个是NSURLSession网络请求系统默认的缓存类NSURLCache自动生成的,非图片的磁盘缓存。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# react
# native图片缓存
# reactnative
# 图片缓存
# React 源码调试方式
# react 源码中位运算符的使用详解
# 使用VScode 插件debugger for chrome 调试react源码的方法
# 浅谈react-router@4.0 使用方法和源码分析
# 用React-Native+Mobx做一个迷你水果商城APP(附源码)
# 深入理解react-router@4.0 使用和源码解析
# React之echarts-for-react源码解读
# 加载
# 的是
# 都是
# 看着
# 是个
# 回调
# 是有
# 三种
# 只需要
# 不需
# 想让
# 自带
# 约为
# 都为
# 则会
# 再将
# 第二种
# 先看
# 自动生成
# 出在
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
移动端脚本框架Hammer.js
Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试
三星、SK海力士获美批准:可向中国出口芯片制造设备
JavaScript模板引擎Template.js使用详解
如何在Tomcat中配置并部署网站项目?
如何用狗爹虚拟主机快速搭建网站?
Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】
Python结构化数据采集_字段抽取解析【教程】
Laravel如何实现API资源集合?(Resource Collection教程)
制作电商网页,电商供应链怎么做?
宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法
Laravel如何使用Service Container和依赖注入?(代码示例)
Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置
WEB开发之注册页面验证码倒计时代码的实现
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
Windows10如何更改计算机工作组_Win10系统属性修改Workgroup
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
Laravel如何使用Blade模板引擎?(完整语法和示例)
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
如何快速搭建个人网站并优化SEO?
米侠浏览器网页图片不显示怎么办 米侠图片加载修复
详解MySQL数据库的安装与密码配置
如何在IIS中配置站点IP、端口及主机头?
高性价比服务器租赁——企业级配置与24小时运维服务
网站制作价目表怎么做,珍爱网婚介费用多少?
Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
北京的网站制作公司有哪些,哪个视频网站最好?
Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】
消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
如何有效防御Web建站篡改攻击?
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
简历在线制作网站免费版,如何创建个人简历?
创业网站制作流程,创业网站可靠吗?
韩国服务器如何优化跨境访问实现高效连接?
网页设计与网站制作内容,怎样注册网站?
怎么用AI帮你为初创公司进行市场定位分析?
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?
CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
简单实现jsp分页
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
如何在腾讯云免费申请建站?
香港服务器如何优化才能显著提升网站加载速度?

