探究react-native 源码的图片缓存问题

前端之家收集整理的这篇文章主要介绍了探究react-native 源码的图片缓存问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文为xcode模拟器测试,rn版本0.44.3

突然想学习下RN是如何封装ios中的UIImage的,看着看着发现图片的缓存问题是个坑。。。

先看js端图片使用的三种方式,依次排序1、2、3

// 1、 加载远程图片 //2、加载xcode中图片 //3、加载js中图片

1、2必须设置图片宽高,3不需设置。

对应的ios原生端文件是RCTImageViewManager,暴露的属性

);

就是js中Image组件的属性source,在js中设置source会触发该属性的setter方法。进入RCTImageView的

*)imageSources { if (![imageSources isEqual:_imageSources]) { _imageSources = [imageSources copy]; [self reloadImage]; } }

通过此方法中断点打印imageSources,依次得到下面结果:

可见,Image组件加载图片都是采用URL的形式,将图片当作网络资源。不同的是URL的类型:

图片 : http:// 加载xcode资源 : file:// 加载js中图片 : http://localhost:8081

追踪setter方法,到RCTImageLoader.m中的如下方法

图片完成后回调 __weak RCTImageLoader *weakSelf = self; void (^completionHandler)(NSError *,id,BOOL,NSString *) = ^(NSError *error,id imageOrData,BOOL cacheResult,NSString *fetchDate) { __typeof(self) h3Self = weakSelf; if (cancelled || !h3Self) { return; } // 如果imageOrData是图片类型,则直接回调 // 此处,如果是第二种情况,则会满足,其他情况继续走下面方法 if (!imageOrData || [imageOrData isKindOfClass:[UIImage class]]) { cancelLoad = nil; completionBlock(error,imageOrData); return; }

// 在内存中查看是否存在该url对应的字节码图片
if (cacheResult) {
UIImage *image = [[h3Self 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
[[h3Self imageCache] addImageToCache:image
URL:imageURLRequest.URL.absoluteString
size:size
scale:scale
resizeMode:resizeMode
responseDate:fetchDate];
}

cancelLoad = nil;
completionBlock(error_,image);
};
// 具体的解压过程
cancelLoad = [h3Self 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缓存,方法

_decodedImageCache setObject:image forKey:cacheKey cost:bytes]; } }

RCTMaxCachableDecodedImageSizeInBytes是个常量,为1048576,也就是只缓存小于1MB的图片

问题出在cacheKey,查看缓存key的方法

缓存key的生成方法中包含了responseDate,responseDate是网络请求时返回来的

代码如下:

1、3方式每次加载都是一个网络请求,那么网络请求的时间总是变化的,于是responseDate是变化的,cacheKey不唯一,所以虽然系统做了图片的缓存,但是每次取出的都为nil,缓存无效。

2方式加载具体方法在RCTLocalAssetImageLoader.m中,其调用的是RCTUtils的RCTImageFromLocalAssetURL方法

可见是采用[UIImage imageNamed:imageName]的方式加载xcode自带图片,这个是有内存缓存的。

综上,对react-native图片加载

1、3情况,没有内存缓存

2情况有系统默认的内存缓存

所有情况都没有磁盘缓存

想让内存缓存生效,只需要改变cacheKey的生成规则即可。

补充:沙盒下面的Library/Caches/项目bunderId号/fsCachedData文件夹里面会磁盘缓存大于一定值(测试约为5kb)的图片文件,这个是NSURLSession网络请求系统默认的缓存类NSURLCache自动生成的,非图片的磁盘缓存。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

猜你在找的JavaScript相关文章