• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

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

    來源:懂視網 責編:小采 時間:2020-11-27 22:31:55
    文檔

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

    探究react-native 源碼的圖片緩存問題:本文為xcode模擬器測試,rn版本0.44.3 突然想學習下RN是如何封裝ios中的UIImage的,看著看著發現圖片的緩存問題是個坑。 先看js端圖片使用的三種方式,依次排序1、2、3 <Image source={{uri:url}} style={{width:200,h
    推薦度:
    導讀探究react-native 源碼的圖片緩存問題:本文為xcode模擬器測試,rn版本0.44.3 突然想學習下RN是如何封裝ios中的UIImage的,看著看著發現圖片的緩存問題是個坑。 先看js端圖片使用的三種方式,依次排序1、2、3 <Image source={{uri:url}} style={{width:200,h

    本文為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自動生成的,非圖片的磁盤緩存。

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

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

    探究react-native 源碼的圖片緩存問題:本文為xcode模擬器測試,rn版本0.44.3 突然想學習下RN是如何封裝ios中的UIImage的,看著看著發現圖片的緩存問題是個坑。 先看js端圖片使用的三種方式,依次排序1、2、3 <Image source={{uri:url}} style={{width:200,h
    推薦度:
    標簽: 圖片 的圖片 緩存
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 精品久久久久久久中文字幕| 亚洲国产成人精品无码区在线观看 | 黑人精品videos亚洲人| 欧美精品一区二区在线精品 | 性欧洲精品videos| 久久精品无码专区免费| 99精品国产一区二区| 国产精品大白天新婚身材| 国产日产韩国精品视频| 老司机67194精品线观看| 在线中文字幕精品第5页| 欧美成人精品网站播放 | 乱精品一区字幕二区| 中文字幕av日韩精品一区二区| 欧美成人精品第一区二区三区| 精品一区二区三区高清免费观看| 国产精品亚洲αv天堂无码| 99热成人精品免费久久| 日韩精品一区二区三区四区| 久久99精品国产麻豆宅宅| 精品国产污污免费网站| 久久99国产精品久久99果冻传媒 | 国产成人精品免费视频动漫| 国产精品乱码高清在线观看| 国产日韩精品欧美一区| 国产精品jizz视频| 99精品全国免费观看视频..| 国产精品成人在线| 久久亚洲国产欧洲精品一| 九九热在线精品视频| 日韩精品成人一区二区三区| 亚洲精品欧美日韩| 国产99久久九九精品无码| 国产精品国产三级国产潘金莲 | 久久久国产精品亚洲一区| 无码人妻精品一区二区三区66 | 国产cosplay精品视频| 老司机91精品网站在线观看| 欧洲精品视频在线观看| 中文字幕精品视频| 国产亚洲精品线观看动态图|