이미지 메모리를 효율적으로 관리하는 다운 샘플링

서론

iOS를 개발할 때, 이미지를 관리하는 것은 사용자 경험에 있어서 중요한 부분입니다. 높은 해상도를 가지고 있는 이미지들은 메모리 사용량에 큰 영향을 줄 수 있죠. 이번 시간에는 어떻게 효율적으로 이미지 메모리를 줄일 수 있는 방법을 알아보겠습니다.


다운 샘플링이 필요한 상황들

다운 샘플링은 이미지의 퀄리티는 유지하면서 이미지의 사이즈를 줄이고 메모리 사용량을 줄이는 과정입니다. 특히 용량이 큰 이미지들을 작업할 떄 성능의 문제가 생기지 않게 하려면 더욱 필요합니다. 다운 샘플링이 필요한 순간은 다음과 같을 수도 있습니다.

갤러리 사진들

만약 사용자가 해상도가 높은 사진을 갤러리에서 인터렉션 한다면 어떨까요? 이미지를 로딩 하는 것만으로도 메모리 사용량은 큰 부담을 느낄 것입니다. 특히 오래된 기기들이라면 더 심하죠. 다운 샘플링은 이미지 퀄리티를 유지하면서 사용자 경험을 해치지 않고 갤러리에 많은 이미지를 보여줄 수 있게 됩니다.

SNS 피드

SNS앱에서는 유저들이 공유하는 이미지들을 보여줘야합니다. 다운 샘플링은 이런 이미지들의 오버헤드를 발생시키지 않게 하고, 사용자로 하여금 스크롤을 더 부드럽게 할 수 있게합니다.

이미지 업로드

유저가 이미지를 업로드할 때, 다운 샘플링은 이미지 사이즈를 줄일 수 있습니다. 그렇게 되면 이미지 업로드 속도가 빨라지고 결과적으로 유저 만족도가 올라가게 됩니다.


만약 다운 샘플링을 사용하지 않는다면..

만약 사이즈가 작은 Image Container에 해상도가 큰 이미지를 보여준다고 생각해봅시다. 예를 들어서 1000x1000 픽셀의 해상도를 가진 이미지가 있지만, 100x100 픽셀을 가지는 Container에 이미지를 넣고 싶은 것 처럼요. 썸네일 이미지나 프로필 이미지가 될 수 있겠네요!

다운 샘플링을 사용하지 않는다면, 2가지 문제를 직면하게 될 수도 있습니다.

메모리 오버헤드

1000x1000 픽셀의 이미지를 로드하는 것은 메모리에게 상당한 부담이 됩니다. 이런 메모리 할당이 계속 된다면, 메모리 경고나 심하면 앱의 크래시까지 발생할 수 있습니다.

성능에 미치는 영향

해상도가 큰 이미지를 작은 콘테이너에 보여주는 것은 성능면에서도 영향을 끼칩니다. 일단 작은 이미지로 리스케일 하는 과정에서 렌더링 시간이 집중되어 앱의 부드러움에 영향을 미칠 수 있습니다.


다운 샘플링

iOS에서 다운 샘플링을 위한 메서드는 다양하게 제공되지만, 가장 현대적이고 효율적인 접근 법은 바로 iOS10에서 소개된 UIGraphicsImageRenderer을 사용하는 것입니다.

import UIKit

func downsampleImage(at url: URL, to targetSize: CGSize) -> UIImage? {
    let renderer = UIGraphicsImageRenderer(size: targetSize)

    return renderer.image { (context) in
        let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
        if let imageSource = CGImageSourceCreateWithURL(url as CFURL, imageSourceOptions),
           let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {

            let scaleFactor = max(image.width / targetSize.width, image.height / targetSize.height)
            let scaledSize = CGSize(width: image.width / scaleFactor, height: image.height / scaleFactor)

            image.draw(in: CGRect(origin: .zero, size: scaledSize))
        }
    }
}

우리는 downsampleImage라는 이미지 URL과 사이즈에 대한 인자를 받는 메서드를 정의했습니다. 먼저 이미지를 UIImage가 아닌 CGImage로 불러옵니다. 그리고 UIGraphicsImageRenderer의 클로저를 통해 파라미터로 들어온 사이즈를 통해 새로운 이미지로 반환됩니다.

UIGraphicsImageRenderer를 이용한 장점은 다음과 같습니다.

1. 간단함
UIGraphicsImageRenderer는 클로저의 Context를 통해 이미지 프로세싱을 간단하게 조작할 수 있습니다.

2. 메모리 효율성
개발자가 직접 메모리를 관리하는 대신, 이 객체는 iOS 메모리 관리 시스템에 있어서 최적화를 해줍니다.

3. 사이즈와 방향 조절
UIGraphicsImageRenderer는 자동적으로 사이즈와 방향을 조절해줍니다. 따라서 시스템 내에서 작아진 이미지를 반환하는 것을 보장할 수 있습니다.


결론

효율적으로 이미지를 관리하는 것은 사용자 경험에 있어서 중요한 역할을 합니다. UIGraphicsImageRenderer를 이용한 다운 샘플링은 메모리 사용량을 줄이고 성능을 증가할 수 있는 좋은 툴입니다. 다운 샘플링을 구현한다는 것은 앱의 이미지들을 훼손시키지 않고 동시에 성능을 유지할 수 있습니다. 오래된 기기라도요. :)