XLOG

[UIKit] UIImage 효율적으로 사용하기 - 1 본문

Swift/UIKit

[UIKit] UIImage 효율적으로 사용하기 - 1

X_PROFIT 2023. 2. 1. 20:26

프로젝트를 진행하면서 UICollectionView 와 Image를 함께 사용할 일이 많았다.

Asset을 이용하여 사용할 때는 큰 문제가 없었지만, 서버에서 이미지를 불러오면서 그 효율성에 대한 고민을 하기 시작했다.

 

그리기 위해 UIImage, UiImageView 가 어떻게 동작하는지 알아야 겠다는 생각을 했다.

그래서 WWDC18 에 Image and Graphics Best Practice 영상을  확인했다.

 

보통 이미지는 우리 데이터공간, 혹은 네트워크를 통해 다운받아 UIImage로 Load 하여 Decode 한다.

Decode를 하는 과정에서 image사이즈에 따라 image buffer의 크기가 결정된다.

Buffer 란 연속되 메모리 영역이다. Buffer엔 Data Buffer, Image Buffer 등이 있다.

 

즉, UIImage 는 다운 받아 Image에 대한 Data Buffer 를 Image Buffer 로 Decode 를 진행한다. 그 후 UIImageView를 통헤 Render를 하지만 이때 Size를 조정하더라도 Image Buffer 의 사이즈는 원본사이즈 그대로 유지가 되기에 메모리 낭비가 발생하게 된다.

 

이러한 메모리 낭비를 줄이기 위해 우리는 DownSampling 작업을 진행해야 한다.

위의 그림처럼 CGImageSource 로 ImageSize를 조정하여 Thumnail용 UIImage를 리턴하게 하여 Render를 진행하게 된다.

EXAMPLE from WWDC Video

kCGImageSourceShouldCacheImmediately 옵션은 매우 중요하다.

 

그 결과 31.5 MiB 에서 18.4MiB 로 메모리 사용이 줄어든다.

또한 이걸 

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPaht) -> UICollectionViewCell {}

에 적용하여 효율적으로 사용했다고 생각할 수 있는데, 이 방법 또한 권장되지는 않는다고 한다.

그 이유는 컬렉션뷰의 경우 스크롤을 하게 될 경우 새로운 행이 보이면서 url을 통해 image를 다운받아 사이즈를 줄이고 하는 이런 작업들이 매번 일어나는데 이것은 비효율적이면서 불편함을 초래할 수 있다.

 

또한 아이폰은 주사율에 따라 매초 60번 이상의 rerender를 진행하는데 rerender와 image를 불러오는데 있어 차이가 발생하게 되면 자연스럽지 않은 애니메이션을 볼 수 있다. 또한 배터리에도 좋지 않은 영향을 줄 것이다.

 

그렇기에 WWDC 영상에선 두가지 방법을 제시한다.

바로 Prefetching 과 Background decoding / downsampling 이다.

Prefetching을 실행하게 되면 다음 화면을 미리 준비하여 hitching을 대비한다. 또한 메인쓰레드는 View를 담당해야하기에 다른 쓰레드에서 작업을 진행하는 것이다.

 

CollectionView에 저렇게 prefetch하는 함수가 존재하는지 처음알았다. 관련된 사항에 대해 더 자세히 알고 싶으면 wwdc 영상을 또 보라고 한다.........

 

하지만 이 방법또한 완벽한 건 아니다. 큐를 많이 동작시킴으로서 Thread Explosion이 발생할 수 있다. 한번에 image down sampling을 8개 씩 진행하는데 내가 실제 사용할 수 있는것은 2~3개 밖에 존재하지 않을 수 있다.

그렇기에 SerialQueue를 사용하라고 한다.

 

wwdc에 이후 내용엔 Image Sources 를 관리하는 것에 대해서도 나온다.

Asset과 관련된 내용이 나오는데 이건 다음에 포스팅 해야겠다.