react-native 소스 코드 의 이미지 캐 시 문 제 를 탐구 합 니 다.

본 고 는 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/[email protected]')}/> //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 인쇄 를 중단 하고 다음 결 과 를 얻 을 수 있 습 니 다.

이미지 구성 요소 가 그림 을 불 러 오 는 것 은 URL 형식 으로 그림 을 네트워크 자원 으로 사용 하 는 것 을 알 수 있 습 니 다.다른 것 은 URL 의 종류 입 니 다:

           : http://
   xcode     : file://
   js      : http://localhost:8081
setter 추적 방법,RCTImage Loader.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];
 }
}
RCTmax CachableDecoded Image SizeInBytes 는 상수 로 1048576,즉 1MB 이하 의 그림 만 캐 시 합 니 다.
문 제 는 캐 시 키 에서 캐 시 키 를 보 는 방법 입 니 다.

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];
}
캐 시 키 생 성 방법 에는 responseDate 가 포함 되 어 있 습 니 다.responseDate 는 네트워크 요청 시 되 돌아 오 는 것 입 니 다.

responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
1,3 방식 은 불 러 올 때마다 네트워크 요청 입 니 다.그러면 네트워크 요청 시간 은 항상 변 합 니 다.그래서 responseDate 는 변 합 니 다.cacheKey 는 유일 하지 않 기 때문에 시스템 이 그림 의 캐 시 를 만 들 었 지만 꺼 낼 때마다 nil 이 고 캐 시 는 유효 하지 않 습 니 다.
2.구체 적 인 방법 은 RCTLocalAsset ImageLoader.m 에서 RCTUtils 의 RCTImage FromLocalAsset URL 방법 을 호출 합 니 다.

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 번호/fsCacheddeata 폴 더 에 일정 값(약 5kb 테스트)이상 의 그림 과 파일 이 들 어 있 습 니 다.이것 은 NSURLSession 네트워크 요청 시스템 의 기본 캐 시 클래스 NSURLCache 에서 자동 으로 생 성 되 며 그림 이 아 닌 디스크 캐 시 입 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기