ReactNative圖片下載過程(二)

本文承接ReactNative圖片下載過程(一)城侧,繼續(xù)深入研究易遣。源碼在文末,如想直接看可翻至最后嫌佑。

整個圖片的下載過程豆茫,基本思想就是先在模塊里找合適的loader去下載,如果找不到則用RCTNetwork去下屋摇,當(dāng)然我們看源碼肯定不能只懂思想揩魂,一些細(xì)節(jié)處理也是很值得關(guān)注的,比如緩存處理炮温,緩存的訪問限制火脉,取消下載的處理,下載完回調(diào)函數(shù)的線程處理等等柒啤。

1倦挂、處理圖片下載完成后的回調(diào)函數(shù),將回調(diào)函數(shù)放在非主線程中處理白修,防止耗費(fèi)資源妒峦,不得不說其對于輸入的判斷都很到位

  RCTImageLoaderCompletionBlockcompletionHandler = ^(NSError*error, UIImage*image) {
    if([NSThreadisMainThread]) {
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (!cancelled) {
         completionBlock(error, image);
       }
     });
    } elseif(!cancelled) {
     completionBlock(error, image);
   }
 };

2、判斷圖片的URL是否為空兵睛,如果為空則拋出錯誤肯骇。

 if(imageTag.length== 0) {
   completionHandler(RCTErrorWithMessage(@"source.uri should not be an empty string"), nil);
   return^{};
 }

3窥浪、建NSURLCache串行隊列

  // All accessto URL cache must be serialized
  if(!_URLCacheQueue) {
    _URLCacheQueue= dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
  }

4、異步執(zhí)行隊列_URLCacheQueue,初始化URLCache緩存

    if(!_URLCache) {
      _URLCache= [[NSURLCachealloc] initWithMemoryCapacity:5* 1024* 1024// 5MB
                                              diskCapacity:200* 1024* 1024// 200MB
                                                  diskPath:@"React/RCTImageDownloader"];
   }

5笛丙、找到可以執(zhí)行下載操作的loader漾脂,如果找到則執(zhí)行下載操作loadImageForURL:

    RCTImageLoader*strongSelf = weakSelf;
    if(cancelled || !strongSelf) {
      return;
   }
 
    // Findsuitable image URL loader
    NSURLRequest*request = [RCTConvertNSURLRequest:imageTag];
    id<RCTImageURLLoader> loadHandler = [strongSelf imageURLLoaderForURL:request.URL];
    if(loadHandler) {
      cancelLoad = [loadHandler loadImageForURL:request.URL
                                         size:size
                                        scale:scale
                                    resizeMode:resizeMode
                               progressHandler:progressHandler
                             completionHandler:completionHandler]?: ^{};
      return;
   }

6、調(diào)試用胚鸯,檢查網(wǎng)絡(luò)模塊是否可用并能下載圖片

    // Checkif networking module is available
    if(RCT_DEBUG&& ![_bridgerespondsToSelector:@selector(networking)]) {
      RCTLogError(@"No suitableimage URL loader found for %@. You may need to "
                 " import the RCTNetworkinglibrary in order to load images.",
                 imageTag);
      return;
   }
 
    // Checkif networking module can load image
    if(RCT_DEBUG&& ![_bridge.networkingcanHandleRequest:request]) {
      RCTLogError(@"No suitableimage URL loader found for %@",imageTag);
      return;
   }

7骨稿、使用網(wǎng)絡(luò)模塊來下載圖片

    __blockRCTImageLoaderCancellationBlockcancelDecode = nil;
    RCTURLRequestCompletionBlockprocessResponse =
    ^(NSURLResponse*response, NSData*data, NSError*error) {
 
      // 檢查是否有下載出錯或沒有數(shù)據(jù)返回
      if(error) {
        completionHandler(error, nil);
        return;
      } elseif(!data) {
        completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
        return;
     }
 
      // 檢查HTTP請求是否返回錯誤,如有誤則拋出返回的狀態(tài)碼
      if([response isKindOfClass:[NSHTTPURLResponseclass]]) {
        NSInteger statusCode =((NSHTTPURLResponse*)response).statusCode;
        if (statusCode != 200) {
          completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
                                                     code:statusCode
                                                 userInfo:nil], nil);
          return;
       }
     }
 
      // 圖片解碼
      cancelDecode = [strongSelf decodeImageData:data
                                          size:size
                                         scale:scale
                                     resizeMode:resizeMode
                                completionBlock:completionHandler];
   };

8姜钳、添加png后綴

    //判斷請求的url是否為fileURL并且是否沒有后綴坦冠,如果都是則添加后綴png
    if(request.URL.fileURL&& request.URL.pathExtension.length== 0) {
      NSMutableURLRequest*mutableRequest = [request mutableCopy];
      mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
     request = mutableRequest;
   }
 

9、根據(jù)request在responseCache緩存中查找是否已經(jīng)有了緩存哥桥,如果有則執(zhí)行緩存內(nèi)容

    NSCachedURLResponse*cachedResponse = [_URLCachecachedResponseForRequest:request];
    if(cachedResponse) {
      processResponse(cachedResponse.response,cachedResponse.data, nil);
      return;
   }
 

10辙浑、使用RCTNetworkTask來下載圖片

    //調(diào)用network模塊來發(fā)起請求
    RCTNetworkTask*task = [_bridge.networkingnetworkTaskWithRequest:request completionBlock:
                           ^(NSURLResponse*response, NSData*data, NSError*error) {
      if(error) {
        completionHandler(error, nil);
        return;
     }
 
      dispatch_async(_URLCacheQueue, ^{
 
        // 將請求的回應(yīng)緩存起來
        BOOL isHTTPRequest =[request.URL.scheme hasPrefix:@"http"];
        [strongSelf->_URLCache storeCachedResponse:
         [[NSCachedURLResponse alloc] initWithResponse:response
                                                data:data
                                            userInfo:nil
                                       storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
                                      forRequest:request];
 
        // 處理返回的數(shù)據(jù)
        processResponse(response,data, nil);
 
     });
 
   }];

11、開始下載

    task.downloadProgressBlock= progressHandler;
    [task start];
 
   cancelLoad = ^{
      [task cancel];
      if(cancelDecode) {
       cancelDecode();
     }
   };

12拟糕、返回一個可取消下載的block

  return^{
    if(cancelLoad) {
     cancelLoad();
   }
//執(zhí)行1和cancelled的或運(yùn)算然后把結(jié)果存入&cancelled
    OSAtomicOr32Barrier(1, &cancelled);
 };

官方部分源碼

RCTImageLoader.m

- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString*)imageTag
                                             size:(CGSize)size
                                            scale:(CGFloat)scale
                                       resizeMode:(UIViewContentMode)resizeMode
                                    progressBlock:(RCTImageLoaderProgressBlock)progressHandler
                                  completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
{
  __blockvolatileuint32_tcancelled = 0;
  __blockvoid(^cancelLoad)(void) = nil;
  __weakRCTImageLoader*weakSelf = self;
 
  RCTImageLoaderCompletionBlockcompletionHandler = ^(NSError*error, UIImage*image) {
    if([NSThreadisMainThread]) {
 
      //Most loaders do not return on the main thread, so caller is probably not
      //expecting it, and may do expensive post-processing in the callback
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (!cancelled) {
         completionBlock(error, image);
       }
     });
    } elseif(!cancelled) {
     completionBlock(error, image);
   }
 };
 
  if(imageTag.length== 0) {
    completionHandler(RCTErrorWithMessage(@"source.uri should not be an empty string"), nil);
    return^{};
  }
 
  // All accessto URL cache must be serialized
  if(!_URLCacheQueue) {
    _URLCacheQueue= dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
  }
  dispatch_async(_URLCacheQueue, ^{
 
    if(!_URLCache) {
      _URLCache= [[NSURLCachealloc] initWithMemoryCapacity:5* 1024* 1024// 5MB
                                              diskCapacity:200* 1024* 1024// 200MB
                                                  diskPath:@"React/RCTImageDownloader"];
   }
 
    RCTImageLoader*strongSelf = weakSelf;
    if(cancelled || !strongSelf) {
      return;
   }
 
    // Findsuitable image URL loader
    NSURLRequest*request = [RCTConvertNSURLRequest:imageTag];
    id<RCTImageURLLoader> loadHandler = [strongSelf imageURLLoaderForURL:request.URL];
    if(loadHandler) {
      cancelLoad = [loadHandler loadImageForURL:request.URL
                                         size:size
                                        scale:scale
                                    resizeMode:resizeMode
                               progressHandler:progressHandler
                             completionHandler:completionHandler]?: ^{};
      return;
   }
 
    // Checkif networking module is available
    if(RCT_DEBUG&& ![_bridgerespondsToSelector:@selector(networking)]) {
      RCTLogError(@"No suitableimage URL loader found for %@. You may need to "
                 " import the RCTNetworkinglibrary in order to load images.",
                 imageTag);
      return;
   }
 
    // Checkif networking module can load image
    if(RCT_DEBUG&& ![_bridge.networkingcanHandleRequest:request]) {
      RCTLogError(@"No suitableimage URL loader found for %@",imageTag);
      return;
   }
 
    // Usenetworking module to load image
    __blockRCTImageLoaderCancellationBlockcancelDecode = nil;
    RCTURLRequestCompletionBlockprocessResponse =
    ^(NSURLResponse*response, NSData*data, NSError*error) {
 
      //Check for system errors
      if(error) {
        completionHandler(error, nil);
        return;
      } elseif(!data) {
        completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
        return;
     }
 
      //Check for http errors
      if([response isKindOfClass:[NSHTTPURLResponseclass]]) {
        NSInteger statusCode =((NSHTTPURLResponse*)response).statusCode;
        if (statusCode != 200) {
          completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
                                                     code:statusCode
                                                 userInfo:nil], nil);
          return;
       }
     }
 
      //Decode image
      cancelDecode = [strongSelf decodeImageData:data
                                          size:size
                                         scale:scale
                                     resizeMode:resizeMode
                                completionBlock:completionHandler];
   };
 
    // Addmissing png extension
    if(request.URL.fileURL&& request.URL.pathExtension.length== 0) {
      NSMutableURLRequest*mutableRequest = [request mutableCopy];
      mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
     request = mutableRequest;
   }
 
    // Checkfor cached response before reloading
    // TODO:move URL cache out of RCTImageLoader into its own module
    NSCachedURLResponse*cachedResponse = [_URLCachecachedResponseForRequest:request];
    if(cachedResponse) {
      processResponse(cachedResponse.response,cachedResponse.data, nil);
      return;
   }
 
    //Download image
    RCTNetworkTask*task = [_bridge.networkingnetworkTaskWithRequest:request completionBlock:
                           ^(NSURLResponse*response, NSData*data, NSError*error) {
      if(error) {
        completionHandler(error, nil);
        return;
     }
 
      dispatch_async(_URLCacheQueue, ^{
 
        // Cache the response
        // TODO: move URL cache out of RCTImageLoader into itsown module
        BOOL isHTTPRequest =[request.URL.scheme hasPrefix:@"http"];
        [strongSelf->_URLCache storeCachedResponse:
         [[NSCachedURLResponse alloc] initWithResponse:response
                                                data:data
                                            userInfo:nil
                                       storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
                                      forRequest:request];
 
        // Process image data
        processResponse(response,data, nil);
 
     });
 
   }];
    task.downloadProgressBlock= progressHandler;
    [task start];
 
   cancelLoad = ^{
      [task cancel];
      if(cancelDecode) {
       cancelDecode();
     }
   };
 
 });
 
  return^{
    if(cancelLoad) {
     cancelLoad();
   }
    OSAtomicOr32Barrier(1, &cancelled);
 };
}

如果你也對ReactNative感興趣判呕,歡迎一起研究。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末送滞,一起剝皮案震驚了整個濱河市侠草,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌犁嗅,老刑警劉巖边涕,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異褂微,居然都是意外死亡奥吩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蕊梧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霞赫,“玉大人,你說我怎么就攤上這事肥矢《怂ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵甘改,是天一觀的道長旅东。 經(jīng)常有香客問我,道長十艾,這世上最難降的妖魔是什么抵代? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮忘嫉,結(jié)果婚禮上荤牍,老公的妹妹穿的比我還像新娘案腺。我一直安慰自己,他們只是感情好康吵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布劈榨。 她就那樣靜靜地躺著,像睡著了一般晦嵌。 火紅的嫁衣襯著肌膚如雪同辣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天惭载,我揣著相機(jī)與錄音旱函,去河邊找鬼。 笑死描滔,一個胖子當(dāng)著我的面吹牛陡舅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伴挚,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼灾炭!你這毒婦竟也來了茎芋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜈出,失蹤者是張志新(化名)和其女友劉穎田弥,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铡原,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偷厦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了燕刻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只泼。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卵洗,靈堂內(nèi)的尸體忽然破棺而出请唱,到底是詐尸還是另有隱情,我是刑警寧澤过蹂,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布十绑,位于F島的核電站,受9級特大地震影響酷勺,放射性物質(zhì)發(fā)生泄漏本橙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一脆诉、第九天 我趴在偏房一處隱蔽的房頂上張望甚亭。 院中可真熱鬧贷币,春花似錦、人聲如沸狂鞋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骚揍。三九已至字管,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間信不,已是汗流浹背嘲叔。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抽活,地道東北人硫戈。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像下硕,于是被迫代替她去往敵國和親丁逝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評論 25 707
  • Xutils3.0技術(shù)分享1.這個技術(shù)分享的目的1.首先要讓大家了解Xutil3.0是什么Xtuils3.0的前身...
    wodezhuanshu閱讀 3,119評論 5 9
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫梭姓、插件霜幼、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,107評論 4 62
  • 在這個漂浮的城市里,我們卑微著誉尖,依然渴望飛翔罪既。 也許我們只是需要一個擁抱,用來知道铡恕,我們并不孤單琢感。 不是我們慢,是...
    Andersony閱讀 251評論 0 1
  • 電梯不過是架垂直升降機(jī)探熔,完全可以看作是交通工具的一種驹针,乘客在站點(diǎn)等,到不同的地點(diǎn)下诀艰,有公共汽車的特點(diǎn)牌捷,只不過我們多...
    憑欄聽風(fēng)閱讀 246評論 0 0