Borysarang·2022년 8월 3일

swift

목록 보기
6/7
post-thumbnail

Cache

tags: study

캐시란 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 캐시의 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용한다. 캐시에 데이터를 미리 복사해 놓으면 계산이나 접근 시간 없이 더 빠른 속도로 데이터에 접근할 수 있다. - 위키백과

IOS의 캐시

캐시는 데이터가 저장되거나 로드하는 어디에든 위치할 수 있다(Datbase, CPU, 메모리 하드디스크 등등) IOS 에서는 메모리 캐시와 디스크 캐시 두가지를 지원한다.

Memory Cache

  • IOS에서는 NSCache, URLCache등을 통해 자체적으로 지원하고 있다.
  • 앱을 종료시키면 캐시에서 내려가게 된다.
-NSCacheURLCache
저장 장소메모리메모리, 디스크
방식key-valueURL Request에 매핑된 Response

Disk Cache

  • FileManager를 통해서 사용할 수 있다.
  • 앱이 종료 되어도 디스크 영역에 저장하기 때문에 보존된다.

NSCache와 URLCache

NSCache

메모리 캐싱을 위해 apple에서 제공하는 프레임워크. 키-값 타입으로 구성되어있다. NSCache클래스는 캐시가 시스템 메모리를 너무 많이 사용하지 않도록 하는 다양한 자동 제거 정책을 통합한다. 다른 응용 프로그램에서 메모리가 필요한 경우 이러한 정책은 캐시에서 일부 항목을 제거하여 메모리 사용 공간을 최소화합니다. countLimittotalCostLimit등을 통해서 캐싱할 데이터를 설정할 수 있다.

class NSCache<KeyType, ObjectType> : NSObject where KeyType : AnyObject, ObjectType : AnyObject

키-값 형태라면 Dictionary<String, Any> 으로도 구현 할 수 있지 않을까?
이렇게 직접 구현할 수 있지만 NSCache의 가장 큰 차이점은 메모리를 자동으로 관리해준다는점이다. Dict타입으로 직접 구현할 경우 메모리에서 해제하려면 직접 삭제를 해야하지만 NSCache를 사용하면 자동 제거 정책에 따라 메모리에서 해제하게 된다.

구현

꼭 싱글톤 패턴일 필요는 없지만 여러곳에서 사용됨을 가정하였다.

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

NSString의 키를 갖고, UIImage를 값으로 갖는 NSCache인스턴스를 생성한다.

// 값 얻기, 없다면 nil
ImageCacheManager.shared.object(forKey: cachedKey)
// 저장
ImageCacheManager.shared.setObject(image, forKey: cachedKey)
// 삭제
ImageCacheManager.shared.removeObject(image, forKey: cachedKey)

URLCache

URLRequest타입을 키로 응답데이터를 값으로 갖는 캐시 타입이다. NSCache와 다르게 메모리와 디스크를 복합적으로 사용하여 캐싱한다는 점이다. 온디스크로 저장할 수 있기 때문에 어플리케이션을 재시동해도 캐시 데이터는 남아있을 수 있다.

온디스크 데이터는 앱이 실행되고 있지 않을 때 디스크 공간이 부족하다면 제거될 수 있다.

구현

class ImageCacheManager { 
    static let urlShared = URLCache.shared
    private init() {}
}

위와 동일한 방식으로 구현해보았다.

// 값 얻기
CacheManager.urlShared.cachedResponse(for: request)
// 저장 
CacheManager.urlShared.storeCachedResponse(CachedURLResponse(response: result, data: data), for: request)
// 삭제
CacheManager.urlShared.removeCachedResponse(for: request)

Image의 Extension으로 응용

기존의 이미지를 로드하는 순서는 다음과 같다.
1. 이미지를 다운 받을 수 있는 URL로 URL객체를 생성한다.
2. URL을 기반으로 Request, 응답은 이미지의 Data타입이다.
3. 받아온 Image Data를 UIImage(data:Data)에 넣어 이미지로 만든다.

이제 이미지를 다운로드 받는 url 주소와 실제 받은 data를 캐싱할 것이다.
1. url을 기반으로 NSCache에 존재하는지 확인한다.
2. 해당 url로 캐시에서 불러온 이력이 있다면 즉시 Image의 data를 UIImage로 바꿔 리턴한다.
3. 없다면 URL을 기반으로 Request, 응답으로 이미지의 Data타입을 받는다.
4. 이 url로 받아온 Image data는 캐시에 없는, 처음으로 받아온 이미지이므로 NSCache에 저장한다.
5. 그 후 Image를 리턴한다.

NSCache에서 해당 url을 키값으로 검색하여 리턴하는것이 대게(절대적인것은 아니므로) 네트워킹 시간보다는 짧으므로
고화질 이미지를 기준으로 테스트해보면 시간이 단축 되는것을 볼 수 있었다.

func setImageUrl(_ url: String) {
    DispatchQueue.global(qos: .background).async {
        let cachedKey = NSString(string: url)
        if let cachedImage = ImageCacheManager.shared.object(forKey: cachedKey) {
            DispatchQueue.main.async {
                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()
    }
}

참고

Apple Developer Document - NSCache
[Apple Developer Doucment - URLCache][Cache 위키 백과](https://ko.wikipedia.org/wiki/%EC%BA%90%EC%8B%9C)
jake 블로그
캐시의 데이터 교체 알고리즘에 관하여

0개의 댓글