国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

探究react-native 源碼的圖片緩存問題

2019-11-19 15:41:25
字體:
來源:轉載
供稿:網友

本文為xcode模擬器測試,rn版本0.44.3

突然想學習下RN是如何封裝ios中的UIImage的,看著看著發(fā)現圖片的緩存問題是個坑。。。

先看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會觸發(fā)該屬性的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是圖片類型,則直接回調  // 此處,如果是第二種情況,則會滿足,其他情況繼續(xù)走下面方法 if (!imageOrData || [imageOrData isKindOfClass:[UIImage class]]) {  cancelLoad = nil;  completionBlock(error, imageOrData);  return; }  // 在內存中查看是否存在該url對應的字節(jié)碼圖片 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不唯一,所以雖然系統(tǒng)做了圖片的緩存,但是每次取出的都為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情況有系統(tǒng)默認的內存緩存

所有情況都沒有磁盤緩存

想讓內存緩存生效,只需要改變cacheKey的生成規(guī)則即可。

補充:沙盒下面的Library/Caches/項目bunderId號/fsCachedData文件夾里面會磁盤緩存大于一定值(測試約為5kb)的圖片和文件,這個是NSURLSession網絡請求系統(tǒng)默認的緩存類NSURLCache自動生成的,非圖片的磁盤緩存。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 炎陵县| 松桃| 威海市| 宜兰县| 沙湾县| 芜湖县| 茶陵县| 保康县| 独山县| 武安市| 敦化市| 黄骅市| 离岛区| 年辖:市辖区| 长葛市| 本溪市| 玉环县| 富宁县| 佳木斯市| 南和县| 凤阳县| 富顺县| 尼勒克县| 莆田市| 新郑市| 佛山市| 青岛市| 将乐县| 五峰| 安顺市| 祁门县| 娄烦县| 崇州市| 上蔡县| 上高县| 马龙县| 河东区| 新民市| 来安县| 台东市| 夏河县|