UIImage 이미지 삭제


117

2014 년 2 월 편집 : 이 질문은 iOS 2.0에서 시작되었습니다. 그 이후로 이미지 요구 사항과 처리가 많이 바뀌 었습니다. Retina는 이미지를 더 크게 만들고 로딩을 약간 더 복잡하게 만듭니다. iPad 및 레티 나 이미지에 대한 지원이 내장되어 있으므로 코드에 ImageNamed를 사용해야합니다 .

나는 많은 사람들 imageNamed이 나쁘다고 말하지만 성능이 좋다고 말하는 사람들이 같은 수를 UITableView봅니다. 특히 s를 렌더링 할 때 말입니다 . 참조 이 SO 질문에 예 또는 이 문서 iPhoneDeveloperTips.com에를

UIImageimageNamed방법은 누출에 사용되었으므로 피하는 것이 가장 좋지만 최근 릴리스에서 수정되었습니다. 시스템에서 내 이미지를 캐시 할 수있는 위치와 추가 작업을 수행하고 직접 수행해야하는 위치에 대한 합리적인 결정을 내리기 위해 캐싱 알고리즘을 더 잘 이해하고 싶습니다. 내 현재 기본 이해는 파일 이름 NSMutableDictionary으로 UIImages참조하는 것이 간단하다는 것 입니다. 더 커지고 메모리가 부족하면 훨씬 작아집니다.

예를 들어, 누구든지 뒤에있는 이미지 캐시 imageNamed가 응답하지 않는다는 것을 알고 didReceiveMemoryWarning있습니까? 애플이 이것을하지 않을 것 같지는 않다.

캐싱 알고리즘에 대한 통찰력이 있으면 여기에 게시하십시오.


2
나도. 내가 생각했던 것처럼 SO는 천재로 가득하지 않은 것 같습니다.
Rog

이 문제를 조사하는 데 시간을 투자 한 것 같습니다. 최신 코코아 터치 버전으로 UIImage imageNamed의 부정적인 영향을 보여주는 실험을 수행 했습니까? UITableView를 만들고 많은 (수천 개) 행을 추가하고 모든 행에 다른 이미지를 표시 할 때 성능이 저하되는지 확인합니다. 그러면 사람들이 당신의 발견에 대해 논평 할 수 있습니다.
stefanB

사실 저는 그렇게 많은 실험을하지 않았습니다. 나는 imageNamed를 사용하고 아직이 앱을 메모리 최적화하지는 않았지만 imageNamed를 메모리 돼지로 직접 가리킬 수있는 것이 없습니다. 여기에 imagedNamed에 대해 불평하는 블로그 게시물 몇 개를 지적했으며 더 많은 조치를 취한 사과 보드에 유사한 질문을했습니다. 시간이있을 때 여기에 요약과 링크를 다시 게시하고 회신을받을 수 있다고 생각합니다.
Rog

답변:


85

tldr : ImagedNamed는 괜찮습니다. 메모리를 잘 처리합니다. 그것을 사용하고 걱정하지 마십시오.

2012 년 11 월 편집 :이 질문은 iOS 2.0에서 시작되었습니다. 그 이후로 이미지 요구 사항과 처리가 많이 바뀌 었습니다. Retina는 이미지를 더 크게 만들고 로딩을 약간 더 복잡하게 만듭니다. iPad 및 레티 나 이미지에 대한 지원이 내장되어 있으므로 코드에서 ImageNamed를 사용해야합니다. 이제 후세를 위해 :

Apple Dev Forums 의 자매 스레드 는 더 나은 트래픽을 받았습니다. 특히 Rincewind 는 권한을 추가했습니다.

iPhone OS 2.x에는 메모리 경고 후에도 imageNamed : 캐시가 지워지지 않는 문제가 있습니다. 동시에 + imageNamed : 캐시가 아니라 편의를 위해 많이 사용되었습니다. 이로 인해 문제가 예상했던 것보다 더 확대되었을 것입니다.

경고하면서

속도면에서 무슨 일이 일어나고 있는지에 대한 일반적인 오해가 있습니다. + imageNamed :가 수행하는 가장 큰 일은 소스 파일에서 이미지 데이터를 디코딩하는 것입니다.이 경우 거의 항상 데이터 크기가 크게 증가합니다 (예 : 화면 크기의 PNG 파일은 압축 할 때 수십 KB를 소비하지만 절반 MB 이상을 소비합니다. 압축 해제-너비 * 높이 * 4). 대조적으로 + imageWithContentsOfFile : 이미지 데이터가 필요할 때마다 해당 이미지의 압축을 해제합니다. 상상할 수 있듯이 이미지 데이터가 한 번만 필요하다면 여기에서 아무것도 얻지 못했습니다. 단, 캐시 된 버전의 이미지가 필요한 것보다 오래 걸릴 수 있습니다. 그러나 자주 다시 그려야하는 큰 이미지가있는 경우 대체 방법이 있지만, 내가 주로 권장하는 것은 큰 이미지를 다시 그리는 것을 피하는 것입니다. :)

캐시의 일반적인 동작과 관련하여 파일 이름을 기반으로 캐시를 수행합니다 (따라서 + imageNamed의 두 인스턴스는 동일한 이름을 가진 동일한 캐시 된 데이터에 대한 참조를 생성해야 함). + imageNamed :. iPhone OS 2.xa에서 버그는 메모리 경고가 수신 될 때 캐시가 축소되는 것을 방지합니다.

내 이해는 + imageNamed : 캐시가 iPhone OS 3.0의 메모리 경고를 존중해야한다는 것입니다. 기회가있을 때 테스트하고 그렇지 않은 경우 버그를보고하십시오.

그래서 거기에 있습니다. imageNamed : 창문을 부수거나 자녀를 죽이지 않습니다. 매우 간단하지만 최적화 도구입니다. 슬프게도 이름이 나쁘고 사용하기 쉬운 동등 가치가 없습니다. 따라서 사람들은 그것을 남용하고 단순히 일을 할 때 화가납니다

이를 수정하기 위해 UIImage에 카테고리를 추가했습니다.

// header omitted
// Before you waste time editing this, please remember that a semi colon at the end of a method definition is valid and a matter of style.
+ (UIImage*)imageFromMainBundleFile:(NSString*)aFileName; {
    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
    return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", bundlePath,aFileName]];
}

Rincewind에는 최적화 된 버전을 빌드하기위한 몇 가지 예제 코드도 포함되어 있습니다. 나는 그것이 유지 보수의 가치가 있음을 알 수 없지만 여기에서는 완전성을위한 것입니다.

CGImageRef originalImage = uiImage.CGImage;
CFDataRef imageData = CGDataProviderCopyData(
     CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
CFRelease(imageData);
CGImageRef image = CGImageCreate(
     CGImageGetWidth(originalImage),
     CGImageGetHeight(originalImage),
     CGImageGetBitsPerComponent(originalImage),
     CGImageGetBitsPerPixel(originalImage),
     CGImageGetBytesPerRow(originalImage),
     CGImageGetColorSpace(originalImage),
     CGImageGetBitmapInfo(originalImage),
     imageDataProvider,
     CGImageGetDecode(originalImage),
     CGImageGetShouldInterpolate(originalImage),
     CGImageGetRenderingIntent(originalImage));
CGDataProviderRelease(imageDataProvider);
UIImage *decompressedImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);

이 코드의 단점은 디코딩 된 이미지가 더 많은 메모리를 사용하지만 렌더링이 더 빠르다는 것입니다.


iOS11에서 [UIImage imageNamed :] 이미지가 xcasset 카탈로그에서 오는 경우 캐시에서 이미지를 제거하지 않는 것 같습니다. 이로 인해 메모리 부족으로 인해 충돌이 발생합니다.
Juraj Antas

5

내 경험상 imageNamed에서 만든 이미지 캐시는 메모리 경고에 응답하지 않습니다. mem 관리에 관해서는 가능한 한 간결한 두 개의 응용 프로그램이 있었지만 여전히 mem 부족으로 인해 설명 할 수없는 충돌이 발생했습니다. imageNamed를 사용하여 이미지를로드하는 것을 중단했을 때 두 응용 프로그램 모두 훨씬 더 안정적이되었습니다.

두 응용 프로그램 모두 다소 큰 이미지를로드했지만 전혀 평범하지 않은 것은 아닙니다. 첫 번째 응용 프로그램에서는 사용자가 동일한 이미지로 두 번 돌아올 가능성이 없기 때문에 캐싱을 완전히 건너 뛰었습니다. 두 번째에서는 언급 한대로 UIImage를 NSMutableDictionary에 보관하고 메모리 경고를 받으면 내용을 플러시하는 매우 간단한 캐싱 클래스를 구축했습니다. imageNamed : 그렇게 캐시했다면 성능 업그레이드를 보지 않았어야합니다. 이 모든 것이 2.2에서 실행되었습니다. 3.0이 이에 영향을 미치는지 모르겠습니다.

내 첫 번째 앱에서이 문제에 대한 다른 질문을 찾을 수 있습니다. UIImage 캐시에 대한 StackOverflow 질문

한 가지 다른 참고 사항-InterfaceBuilder는 내부적으로 imageNamed를 사용합니다. 이 문제가 발생하면 염두에 두어야 할 사항.


나는 똑같은 행동을 보았고 파일에서 직접 읽은 것으로 직접 해결되었습니다. 또한 11,456 x 3,226 px, 15MB의 매우 큰 이미지를로드하려고 할 때 발생합니다. 내 이론은 시스템이 ImageNamed 캐시 작업을 통해 부분적으로 메모리가 부족하다는 것입니다. 이 경우에는 핸들링이 내장되어 있지 않습니다.
Dogweather 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.