2014-11-06 2 views
0

UITableViewCells (이 프로젝트에서는 인터넷에서 SDWebImageView 또는 다른 코드를 사용할 수 없음)의 URL에서 이미지를 다운로드하기위한 클래스를 만들었지 만 많은 메모리를 사용하고있는 것처럼 보였습니다. 너무 빨리 로딩. 아무도 문제를 지적 할 수 있습니까?너무 많은 메모리를 사용하는 UITableView 이미지

코드 :

//MyHelper class  
+(NSString *)pathForImage:(NSString *)urlImageString{ 
    if ([urlImageString class] == [NSNull class] || [urlImageString isEqualToString:@"<null>"] || [urlImageString isEqualToString:@""]) { 
     return @""; 
    } 
    NSArray *pathsInString = [urlImageString componentsSeparatedByString:@"/"]; 

    NSString *eventCodeString = [pathsInString objectAtIndex:[pathsInString count] - 2]; 
    NSString *imageNameString = [pathsInString lastObject]; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); 
    NSString *cachePath = [paths objectAtIndex:0]; 

    cachePath = [MyHelper validateString:[cachePath stringByAppendingString:eventCodeString]]; 
    [cachePath stringByAppendingString:@"/"]; 

    return [cachePath stringByAppendingString:imageNameString]; 
} 

+(BOOL)imageExistsForURL:(NSString *)urlString{ 

    if (!([urlString class] == [NSNull class])) 

    { 
     NSString *filePath = [MyHelper pathForImage:urlString]; 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 

     return [fileManager fileExistsAtPath:filePath]; 
    } 

    return false; 
} 

+(void)setAsyncImage:(UIImageView *)imageView forDownloadImage:(NSString *)urlString{ 
    CGRect activityFrame = CGRectMake(0, 0, 60, 60); 
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithFrame:activityFrame]; 
    activity.layer.cornerRadius = activity.frame.size.width/2; 
    activity.clipsToBounds = YES; 

    activity.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; 
    [imageView addSubview:activity]; 
    [activity startAnimating]; 
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(concurrentQueue, ^{ 

     NSData *image; 
     if ([urlString class] == [NSNull class]) { 
      image = nil; 
     } else { 
      image = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]]; 
     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [activity stopAnimating]; 
      [activity removeFromSuperview]; 
      if (image) 
      { 
       [UIView animateWithDuration:0.9 animations:^{ 
        imageView.alpha = 0; 
        imageView.image = [UIImage imageWithData:image]; 
        imageView.alpha = 1; 
       }]; 
      NSString *filePath = [MyHelper pathForImage:urlString]; 
      NSError *error; 
      [image writeToFile:filePath options:NSDataWritingAtomic error:&error]; 

      } 
      else 
      { 
       imageView.image = [UIImage imageNamed:@"icn_male.png"]; 
      } 
     }); 
    }); 
} 

+(NSString *)validateString:(NSString *)string{ 
    if (string == (id)[NSNull null] || string.length == 0) 
     return @""; 

    return string; 
} 

+ (UIImage*)imageWithImage:(UIImage*)image 
       scaledToSize:(CGSize)newSize; 
{ 
    float proportion; 
    if (image.size.height > image.size.width) { 
     proportion = image.size.height/newSize.height; 
    } else { 
     proportion = image.size.width/newSize.width; 
    } 

    UIGraphicsBeginImageContext(newSize); 
    [image drawInRect:CGRectMake(newSize.width - (image.size.width/proportion), 
           newSize.height/2 - (image.size.height/proportion)/2, 
           image.size.width/proportion, 
           image.size.height/proportion)]; 
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return newImage; 
} 

이 코드를 사용 : 당신이 대형 이미지를 사용하고 있는지 지금은 분명하기 때문에

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *cellIdentifier = @"MyCell"; 
    MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; 


    if ([MyHelper imageExistsForURL:photoURLString ]) { 
     UIImage *image = [UIImage imageWithContentsOfFile:[MyHelper pathForImage:photoURLString]]; 
     eventImageView.image = [MyHelper imageWithImage:image scaledToSize:CGSizeMake(60, 60)]; 
    } else { 
     [MyHelper setAsyncImage:eventImageView forDownloadImage:photoURLString ]; 
    } 
} 
+0

앱을 프로필 링하기 위해 Instruments를 사용하는 것이 좋습니다. 분명히 이미지가 1000x1000 픽셀이고 자동으로 100x100 이미지보기에 맞게 크기가 조정되는 경우 문제가 발생합니다. – dandan78

+0

네, 프로필을 사용했고 당신이 말한 것과 같은 경우가 있습니다. 이 경우에 가장 적합한 방법은 무엇입니까? 다른 더 좋은 방법이 있습니까? – Claudio

답변

1

을,이 솔루션은 당신의 이미지에있을 필요가 얼마나 큰 파악하는 것입니다 앱을 멋지게 꾸밀 수 있습니다.

시스템의 서버 쪽 부분을 얼마만큼 변경할 수 있는지에 따라 몇 가지 조치가 있습니다.

  • 고해상도의 경우 (3x) 최적의 크기로 이미지를 사용하고 2x 및 1x 장치에서 크기 조정을 수행합니다. 이것은 약간 낭비입니다.

  • 이미지 파일 이름에 기기 유형 (2x, 3x 등을 추가 할 수 있음)에 적합한 크기의 이미지를 얻을 수있는 몇 가지 구성표를 만듭니다. 아마 가장 좋은 선택입니다.

  • 클라이언트 측에서 크기를 조정하십시오. 이것은 다소 CPU 집약적 일 수 있으며 불필요하게 많은 작업을 수행 할 것이기 때문에 아마 제 생각에는 최악의 접근 방법 일 것입니다. 그러나 서버 작동 방식을 변경할 수 없으면 이것이 유일한 옵션입니다.

코드의 또 다른 문제점은 UI를 차단하는 주/UI 스레드에서 크기 조정을하고 있다는 것입니다. UI는 차단됩니다. 주 스레드에서 긴 작업을 수행하지 마십시오.

dispatch_async 또는 NSOperation 및 순차적 대기열을 사용하여 백그라운드 스레드에서 메모리 사용을 줄이려면이 작업을 수행해야합니다. 이미지가 준비되면 이미지보기를 업데이트하고 셀이 계속 표시되는지 여부 등을 고려해야하므로 새로운 문제가 발생할 수 있습니다. 나는 잠시 뒤로 멋진 블로그 게시물을 발견 했으므로 웹 검색을 제안합니다.

그러나 이미지가 정말 거대하면 프록시 서버를 설정 한 다음 주 서버 대신 크기가 조정 된 이미지를 가져 오는 것이 좋습니다. 물론이 경우 지적 재산권 문제를 고려해야합니다.

+0

내 문제는 : 서버 측에서 이미지의 크기를 조정할 수 없습니다. 클라이언트 크기. 내가 사용하고있는이 코드를 사용하는 대신 크기를 조정하는 다른 방법이 있습니까? – Claudio

관련 문제