[iOS] 이미지 캐시 처리

Han's·2023년 9월 10일
0
post-thumbnail

NSCache란?

NSCache는 주로 Memory Caching에 사용되는 클래스로, 메모리에서 해제될 때 자동으로 캐시된 내용이 제거됩니다. 메모리 부족 시 NSCache는 자동적으로 객체를 제거하여 메모리를 효율적으로 관리하며, 간단하게 사용할 수 있는 인터페이스를 제공합니다.

  • 특징
  1. Key-Value 쌍 저장
    특정 키로 연결된 값을 저장하고 나중에 해당 키로 값을 검색할 수 있습니다.
  2. Thread-Safe
    NSCache는 Thread-Safe하게 동작하므로 여러 스레드에서 동시에 접근해도 안전합니다.


이미지 캐시 처리의 장점

고화질, 고용량의 이미지를 계속해서 다운로드하게 되면 사용자의 네트워크 리소스를 계속 소모하는 것은 물론, 다운로드가 완료되기까지 걸리는 시간도 낭비됩니다.
따라서 애플리케이션에서 다운로드한 이미지를 캐싱하여 저장해두면, 한 번 다운로드했던 이미지는 나중에 별도의 리소스를 소모할 필요 없이 빠르게 보여줄 수 있는 장점이 있습니다.

이미지 캐시를 사용하는 이유

TableView, CollectionView에서 사용자가 뷰를 스크롤 시 같은 이미지를 요청하는 경우가 생기고, 이때 Cache를 통해서 이미지에 해당하는 URL은 API를 한 번만 호출하도록 하기 위함입니다.

이미지 캐시 처리 방법

  1. Memory Caching
    앱의 메모리 영역의 일부분을 Caching에 사용하는 것

    • 단점
      앱이 종료되어 메모리에서 해제되면 이 영역에 있던 리소스들은 OS에 반환되면서 Memory Caching 되어 있던 리소스들은 사라집니다.

  2. Disk Caching
    데이터를 파일 형태로 디스크에 저장하는 것
    Disk Cache는 보통 FileManager 객체를 사용하여 데이터를 파일 형태로 디스크에 저장하거나 UserDefaults, CoreData를 사용합니다.

    • 장점
      앱을 껐다 켜도 데이터가 사라지지 않는다.
      ex) 인스타그램, 페이스북에서 네트워크 연결이 되어있지 않은 상태에서도 일정 부분 피드를 볼 수 있다.

    • 단점
      Disk Caching이 반복적으로 발생하면 앱이 차지하는 용량이 커진다.


코드

  • ImageCacheManager
import UIKit
import Alamofire

final class ImageCacheManager {
    static let shared = ImageCacheManager()
    private init() { }
    
    private let cache = NSCache<NSURL, UIImage>()
    
    func loadImage(url: String) async -> UIImage? {
        guard let url = URL(string: url) else { return nil }
        // Cache에 저장된 이미지가 있는 경우
        if let image = cachedImage(url: url) {
            return image
        }
        // Cache에 저장된 이미지가 없는 경우
        let dataTask = AF.request(url, method: .get)
            .serializingData()
        
        switch await dataTask.result {
        case .success(let data):
            let image = UIImage(data: data)
            cachingImage(url: url, image: image)
            return image
            
        case .failure(let error):
            print(error.localizedDescription)
            return nil
        }
    }
    
    private func cachingImage(url: URL, image: UIImage?) {
        guard let image = image else { return }
        cache.setObject(image, forKey: url as NSURL)
    }
    
    private func cachedImage(url: URL) -> UIImage? {
        cache.object(forKey: url as NSURL)
    }
}

  • ThumbnailCell
final class ThumbnailCell: UICollectionViewCell {

	// 생략
    
    func configure(data: Thumbnails.Item) {
        let url = data.snippet.thumbnails.high.url
        let channelID = data.snippet.channelId
        Task {
            let image = await ImageCacheManager.shared.loadImage(url: url)
            imageView.image = image
        }
        titleLabel.text = data.snippet.title
        subTitleLabel.text = data.snippet.description
    }
}

이미지를 요청하면 먼저 Cache에 저장된 이미지가 있는지 확인한 후 이미지가 있다면 해당 이미지를 return 하고, Cache에 저장된 이미지가 없다면 서버로부터 데이터를 가져오고 나서 Cache에 이미지를 저장하는 방식으로 구현했습니다.

profile
🍎 iOS Developer

0개의 댓글