[iOS-swift] Cache와 NSCache 개념

mmim·2022년 11월 11일
2

🎯cache란?

캐시(cache, 문화어: 캐쉬, 고속완충기, 고속완충기억기)는 컴퓨터 과학에서 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 캐시의 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용한다. 캐시에 데이터를 미리 복사해 놓으면 계산이나 접근 시간 없이 더 빠른 속도로 데이터에 접근할 수 있다.
캐시는 시스템의 효율성을 위해 여러 분야에서 두루 쓰이고 있다.

출처: 위키백과 - 캐시

위 설명처럼 캐시는 데이터에 접근하는 시간을 줄이려고 사용한다.

📌 iOS에서 사용하는 Cache

크게 메모리 캐시(memory cache)와 디스크 캐시(disk cache)로 나뉜다
😎 iOS 개발자로써 가장 많이 접하게 되는 cache는 단언컨데 image cache일 것임 -> 메모리/디스크 캐시를 통한 이미지 캐싱 과정까지 알아보자

1️⃣ 메모리 캐시(memory cache)

  • iOS에서는 NSCache를 통해 메모리 캐시를 관리함
  • 앱이 종료되면 메모리가 해제 -> 저장한 데이터가 날아감
  • 저장공간이 적다 ⬇️ -> 처리속도는 빠르다 ⬆️

2️⃣ 디스크 캐시(disk cache)

  • FileManager객체를 사용하여 데이터를 파일 형태로 디스크에 저장
  • 또는 UserDefaults, CoreData를 사용
  • 디스크에 파일 형태로 저장하기 때문에 앱을 종료해도 데이터가 남음
  • 저장공간이 크다 ⬆️ -> 처리속도는 비교적 느림 ⬇️
    (😎물론 네트워크를 이용한 데이터 다운로드보단 훨씬 빠름)

이미지 캐싱 과정

이미지 캐싱은 데이터 처리속도를 최대한 높이고, 데이터가 차지하는 저장공간을 최소화하는 방향으로 설계되어야 함.
따라서 아래와 같은 순서로 이미지 캐싱이 진행됨.
실제로 Kingfisher 이러한 순서로 만들어진 라이브러리!!!

  1. 필요한 이미지가 생김
  2. 메모리 캐시에서 해당 이미지를 검색
  3. 없는 경우, 디스크 캐시에서 해당 이미지를 검색
  4. 없는 경우, URLString으로 이미지를 네트워크 다운로드
  5. 메모리 캐시와 디스크 캐시에 해당 이미지를 저장
  6. 다음 번 요청시에는 메모리 캐시에서 이미지를 불러옴
  7. 프로세스(앱) 재시작 이후의 요청에는 디스크 캐시에서 불러온 후 메모리 캐시에 추가

📌 NSCache란?

key-value쌍을 임시로 저장하는데 사용되는 변경 가능한 Collection

  • NSCache는 자체적으로 시스템 메모리를 너무 많이 사용하지 않도록 자동으로 제거되는 정책을 소유
    - 다른 응용 프로그램에서 메모리가 필요한 경우 이러한 정책은 캐시에서 일부 항목을 제거하여 메모리 사용 공간을 최소화
  • 객체와 달리 캐시는 저장된 key 객체를 복사하지 않는 특징이 존재
  • 디폴트로 캐시 객체는 컨텐츠가 삭제되면 자동으로 제거 (변경 가능)

🛠 이미지 캐시 방법

  • 아래와 같이 NSCache 인스턴스를 생성하고
    setObject, Object 메서드를 통해 이미지 저장/획득할 수 있음
// NSCache 객체 생성
let imageCache = NSCache<NSString, UIImage>()

// NSCache를 이용해서 이미지를 메모리 캐시에 저장
imageCache.setObject(object, forKey: key as NSString)

// NSCache를 이용해서 메모리 캐시에서 이미지 획득 
imageCache.object(forKey: key as NSString)

💡 key는 image의 urlString값을 사용

🛠 실제로 적용해보자!

  • NSCahce는 key-value쌍을 임시로 저장하는데 사용되는 변경 가능한 Collection임
    따라서 앱이 실행되는 동안 하나의 NSCache Collection에 이미지가 저장되고 가져오고 해야함

이럴때 쓰라고 있는게 싱글턴!!! 싱글턴으로 된 ImageCacheManager 객체를 만들어주자!!!

final class ImageCacheManager {
    static let shared = NSCache<NSString, UIImage>()
    private init() {}
}
  • 보통 이미지를 setting 할 때는 아래처럼 할당해줌
let someImageView = UIImageView()
someImageView.image = UIImage()
  • 만약 UIImageView를 extesion하고 메서드에 image를 set하도록 구현하면 편하게 사용할 수 있음
extension UIImageView {
    func loadImage() {
        self.image = UIImage()
    }
}

someImageView.loadImage()

이제 진짜로 구현해보자

1️⃣ 이미지를 네트워크에서 다운로드하기 전에 캐시된 이미지가 있는지 검색
2️⃣ 캐시된 이미지가 있다면 -> 캐시된 이미지를 가져와서 image에 적용
3️⃣ 캐시된 이미지가 없다면 -> 네트워크 통신을 하여 이미지를 다운로드
4️⃣ 새롭게 다운로드된 이미지 캐싱

extension UIImageView {
    func loadImage(_ imageUrlString: String) {
        let cacheKey = NSString(string: imageUrlString) 
        // 1️⃣ 
        if let cachedImage = ImageCacheManager.shared.object(forKey: cacheKey) { 
        // 2️⃣
            self.image = cachedImage
            return
       
        // 3️⃣
        NetworkManager.shared.loadImage(imageID: imageUrlString) { result in 
            switch result {
            case .success(let data):
                if let data = data, let image = UIImage(data: data) {
                    DispatchQueue.main.async { [weak self] in
         				// 4️⃣
        			    ImageCacheManager.shared.setObject(image, forKey: cacheKey)
                        self?.image = image
                    }
                }
            case .failure:
                self.image = UIImage()
                return
            }
        }
    }
}

참고
https://jryoun1.github.io/swift/Cache/
https://ios-development.tistory.com/658

profile
예비 iOS 개발자의 기록

0개의 댓글