관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] NSCache 개념, 이미지 캐시 (Image cache), (memory cache, disk cache) 본문

iOS 응용 (swift)

[iOS - swift] NSCache 개념, 이미지 캐시 (Image cache), (memory cache, disk cache)

jake-kim 2021. 8. 8. 23:57

일반적인 Cache 방법

  • memory cache(메모리에 존재하는지 체크) 없다면 > disk cache(디스크에 존재하는지 체크) 있으면 Memory에 저장 후 캐싱, 없다면 > 서버통신
  • memory cache 방법 중 하나는 NSCache 사용
  • disk cache는 보통 FileManager객체를 사용하여 데이터를 파일 형태로 디스크에 저장하거나 UserDefaults, CoreData 사용

NSCache란?

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

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

/// NSCache 객체 획득
private let imageCache = NSCache<NSString, UIImage>()

/// 캐싱 - lastPathComponent로 파일명만 획득
imageCache.setObject(image, forKey: url.lastPathComponent as NSString)

이미지 캐시 방법

  • 캐시를 저장해놓을 singleton 클래스 준비
  • singleton에 url을 저장해놓고 해당 url에 대한 API 호출이 있을 경우, 해당 singleton클래스를 확인하여 캐싱

이미지 캐시 구현

  • 캐시하는 singleton 클래스 정의
class ImageCacheManager {
    static let shared = NSCache<NSString, UIImage>()
    private init() {}
}
  • 서버 통신을 통해 이미지를 불러오는 메소드를 UIImageView의 extension으로 구현
    • URLSession 개념은 여기 참고
extension UIImageView {
    func setImageUrl(_ url: String) {
        DispatchQueue.global(qos: .background).async {
            guard let url = URL(string: url) else { return }

            /// API 통신
            URLSession.shared.dataTask(with: url) { (data, result, error) in

                /// API통신에서 에러가 난 경우
                guard error == nil else {
                    DispatchQueue.main.async { [weak self] in
                        self?.image = UIImage()
                    }
                    return
                }

                /// API가 정상 동작한 경우
                DispatchQueue.main.async { [weak self] in
                    if let data = data, let image = UIImage(data: data) {
                        self?.image = image
                    }
                }
            }.resume()
        }
    }
}
  • 캐싱 적용
extension UIImageView {
    func setImageUrl(_ url: String) {
        DispatchQueue.global(qos: .background).async {

            /// cache할 객체의 key값을 string으로 생성
            let cachedKey = NSString(string: url)

            /// cache된 이미지가 존재하면 그 이미지를 사용 (API 호출안하는 형태)
            if let cachedImage = ImageCacheManager.shared.object(forKey: cachedKey) {
                self.image = cachedImage
                return
            }

            guard let url = URL(string: url) else { return }
            URLSession.shared.dataTask(with: url) { (data, result, error) in
                guard error == nil else {
                    DispatchQueue.main.async { [weak self] in
                        self?.image = UIImage()
                    }
                    return
                }

                DispatchQueue.main.async { [weak self] in
                    if let data = data, let image = UIImage(data: data) {

                        /// 캐싱
                        ImageCacheManager.shared.setObject(image, forKey: cachedKey)
                        self?.image = image
                    }
                }
            }.resume()
        }
    }
}

* TableView에서 NSCache와 async를 이용하여 효율적으로 이미지를 불러오는 방법: https://ios-development.tistory.com/659

* 참고

https://hryang.tistory.com/29

https://developer.apple.com/documentation/foundation/nscache

Comments