study record

[iOS] NSCache란? 본문

iOS/iOS 정리

[iOS] NSCache란?

asong 2022. 3. 26. 18:10

캐싱이란?

캐싱은 재사용될 수 있을만한 자원을 특정 영역에 저장해놓은 것을 의미한다. 캐싱된 데이터가 있다면 추가적인 자원을 소모하지 않고 캐싱 데이터를 가져다 쓸 수 있기 때문에 자원을 절약할 수 있고 애플리케이션의 처리 속도가 향상된다.

 

모바일 애플리케이션에서 매우 고화질의 이미지를 반복해서 보여주어야 할 때 캐싱이 없다면, 고화질, 고용량의 이미지를 계속해서 다운로드하기 때문에 사용자의 네트워크 리소스를 소모하고, 다운로드 완료까지의 시간동안 사용자는 이미지를 확인할 수 없다. 

하지만 다운로드 받은 이미지를 캐싱하여 저장해둔다면, 별도의 리소스를 소모하지 않고 이미지를 빠르게 보여줄 수 있다.

 

메모리 캐싱 VS 디스크 캐싱

메모리 캐싱애플리케이션의 메모리 영역 일부분을 캐싱에 사용하는 것이다. 애플리케이션이 종료되어 메모리에서 해제되면 이 영역의 리소스들은 OS에 반환되면서 메모리 캐싱되어 있던 리소스들은 사라진다.

 

반면 디스크 캐싱데이터를 파일 형태로 디스크에 저장하는 것이다. 디스크 캐싱이 반복적으로 발생하면 애플리케이션이 차지하는 용량이 커지지만, 앱을 껐다 켜도 데이터가 사라지지 않는다. 예시 -> 카카오톡 대화방의 사진, 동영상들 캐시 삭제하면 용량이 줄어든다.

 

Cache 캐시 방법

메모리 캐시 (메모리에 존재하는지 체크) -> 없다면 디스크 캐시(디스크에 존재하는지 체크) -> 있으면 메모리에 저장 후 캐싱, 없다면 서버통신

 

메모리 캐시 방법 중 하나는 NSCache 사용

디스크 캐시는 보통 FileManager 객체를 사용하여 데이터를 파일 형태로 디스크에 저장하거나 UserDefaults, CoreData 사용

 

NSCache란?

key - value 쌍을 임시로 저장하는데 사용되는 변경가능한 컬렉션. 자원이 부족할 때 삭제 대상이 된다.

class NSCache<KeyType, ObjectType> : NSObject where KeyType : AnyObject, ObjectType : AnyObject
  • NSCache는 자체적으로 시스템 메모리를 너무 많이 사용하지 않도록 자동으로 제거되는 정책을 가지고 있다. 다른 응용 프로그램에서 메모리가 필요한 경우 캐시에서 일부 항목을 제거하여 메모리 사용 공간을 치소화하는 방식이다.
  • NSMutableDictionary 객체와 달리 캐시는 저장된 Key 객체를 복사하지 않는 특징이 있다.
  • 디폴트로 캐시 객체는 컨텐츠가 삭제되면 자동으로 제거된다.
  • 캐시를 잠글(lock) 필요 없이 별도 스레드에서 캐시 항목을 추가, 삭제, 검색할 수 있다.
  • 연결리스트(LinkedList)와 딕셔너리를 함께 사용한다. 
    • 캐싱은 중간에 있는 데이터를 추가, 삭제가 빈번하게 발생하여 배열을 사용하면 데이터를 앞으로 당기거나 미는 작업이 필요하다. 하지만 연결리스트를 사용하여 추가, 삭제 과정을 빠르게 진행할 수 있다.
    • 반면 연결리스트는 탐색에 O(n)이 걸리므로 딕셔너리를 사용하여 key로 데이터를 접근할 때 O(1)으로 빠르게 탐색한다.
  • 한계를 넘어갈 경우 적은 용량의 데이터부터 삭제한다.

 

이미지 캐시 방법

캐시를 저장해 놓을 싱글톤 클래스를 준비한다.

싱글톤에 url을 저장해 놓고 해당 url에 대한 API 호출이 있을 경우, 해당 싱글톤 클래스를 확인하여 캐싱한다.

class ImageCacheManager {
    static let shared = NSCache<NSString, UIImage>()
    private init() {}
}

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()
        }
    }
}

 

NSDictionary와의 차이점

1. 자동으로 메모리 관리

NSCache는 시스템 메모리가 차면 자동으로 캐시의 메모리를 정리해준다. 앱에서 메모리가 부족한데 메모리를 더 사용하려고 하면 데이터를 지우고 메모리를 해제한다. NSCache의 자동 제거 정책은 totalCostLimit 혹은 countLimit을 설정하여 수동적으로 관리할 수 있다.  여기에 NSCache에는 setObject(_:forKey:cost:) method를 이용해 개발자가 임의로 cost를 부여하여 삭제의 우선순위를 정할 수 있다. (cost가 낮은 순서대로 삭제 됨)

 

NSDictionary는 메모리가 부족하다는 시스템 경고를 받으면 메모리 정리 코드를 미리, 직접 작성해야 한다.

 

2. Thread - Safe

NSCache는 Thread-safe 하기 때문에 Cache 데이터를 읽고 쓰고 지울 때마다 따로 lock을 해줄 필요가 없다. 즉 동시에 여러 쓰레드가 접근하더라도 각자 lock을 잡을 필요가 없다.

NSDictionary는 Thread-safe하지 않아서 데이터가 접근할 때 따로 lock 처리를 해줘야 한다.

 

3. Retain Key

NSCache는 Key를 복사하지 않고 리테인한다.

Key가 복사를 지원하지 않는 객체일 수 있기 때문에 이러한 객체도 포용하기 위해서이다.

Dictionary는 Key 값을 copy하지만 NSCache는 retain count만 증가시킨다.

 

 

 

참고: 

https://ios-development.tistory.com/658

https://caution-dev.github.io/ios/2019/04/07/NSCache.html

https://velog.io/@ryalya/iOS-CS-Study-Cache-Memory%EB%9E%80

'iOS > iOS 정리' 카테고리의 다른 글

[iOS] UIView의 Layer란?  (0) 2022.04.01
[iOS] UIResponder  (0) 2022.03.30
iOS App 실행 과정  (0) 2022.03.25
[iOS] View의 생명주기  (0) 2022.03.23
dequeueReusableCell(withIdentifier:for:) 의미와 장점  (0) 2022.03.17