
NSCache는 간단하게 메모리에 저장되는 객체를 관리하는 가변 컬렉션이다.
메모리가 부족 할 시에 시스템이 자동으로 접근하여 저장된 객체를 임의로 제거가 가능하다.
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100 // 최대 100개 객체 저장
cache.totalCostLimit = 50_000 // 총 비용 제한 (예: 바이트 단위)
func loadImage(for key: String) -> UIImage? {
if let image = cache.object(forKey: key as NSString) {
return image
}
// (네트워크 다운로드 또는 디스크 로드 후)
let downloadedImage = UIImage(named: key)!
let cost = downloadedImage.pngData()?.count ?? 0
cache.setObject(downloadedImage, forKey: key as NSString, cost: cost)
return downloadedImage
}
NSCacheDelegate를 통한 제거 직전 동작 선언 가능Thread Safe
NSCache 내부적으로 동기화 매커니즘이 구현되어 있기 때문에 별도의 락, 동기화 코드를 작성하지 않더라도 캐시에 추가, 삭제, query가 가능함을 명시하고 있다.
URLCache란 네트워크 요청에 대한 응답을 메모리 또는 디스크에 자동으로 저장해주는 클래스이다.
let memoryCapacity = 20 * 1024 * 1024 // 메모리 캐시: 20 MB
let diskCapacity = 100 * 1024 * 1024 // 디스크 캐시: 100 MB
let cache = URLCache(memoryCapacity: memoryCapacity,
diskCapacity: diskCapacity,
diskPath: "myCache")
URLCache.shared = cache // shared 객체로 전역에서 접근 가능하게도 할 수 있음
let configuration = URLSessionConfiguration.default
configuration.urlCache = URLCache.shared // 위에서 설정한 공유 캐시 사용
configuration.requestCachePolicy = .useProtocolCachePolicy
let session = URLSession(configuration: configuration)
let url = URL(string: "https://example.com/data.json")!
var request = URLRequest(url: url)
request.cachePolicy = .useProtocolCachePolicy // 개별 요청에도 캐시 정책 지정 가능
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print("Network error:", error)
return
}
guard let httpResponse = response as? HTTPURLResponse,
let data = data else { return }
// (1) 자동 캐시 동작:
// 서버가 적절한 캐시 헤더를 반환했다면,
// URLSession이 자동으로 URLCache.shared에 저장합니다.
// (2) 수동 캐시 저장 예시:
let cachedResponse = CachedURLResponse(response: httpResponse, data: data)
URLCache.shared.storeCachedResponse(cachedResponse, for: request)
// → 필요에 따라 직접 캐시를 조작할 수도 있습니다. :contentReference[oaicite:2]{index=2}
}
task.resume()
만약 서버 응답의 헤더에 캐시 허용 헤더가 존재하면, URLSession이 자동으로 URLCache에 저장한다.
수동으로 저장하기 위해 CachedURLResponse 클래스 객체를 생성하여 서버 측 응답인 httpResponse와 data를 가지는 객체로 URLCache에 storeCachedResponse를 호출하여 저장한다.
이때 저장 될 때는 request를 key로 하여 캐시에 저장된 데이터를 찾게 된다.
response: 원본 URLResponse 객체로, HTTP 상태 코드, 헤더 등 응답 메타데이터를 포함data: 실제 응답 데이터 (Data 타입)userInfo: 캐시된 응답과 관련된 추가 정보를 저장할 수 있는 딕셔너리 (옵션)storagePolicy: 캐시 저장 정책으로, 메모리만 사용할지 또는 디스크에도 저장할지를 결정합니다..allowed: 메모리와 디스크 모두에 저장을 허용합니다..allowedInMemoryOnly: 메모리에만 저장하고, 디스크에는 저장하지 않습니다..notAllowed: 캐시에 저장하지 않습니다.| 항목 | URLCache | NSCache |
|---|---|---|
| 주 용도 | 네트워크 응답 (URLRequest ↔ CachedURLResponse) | 생성 비용이 큰 임시 객체 (예: 이미지, 계산 결과) |
| 저장 위치 | 메모리 및 디스크 (둘 다 가능) | 메모리 전용 |
| 자동 제거 정책 | 없음 (명시적 제거 필요) | 있음 (메모리 부족 시 자동 제거) |
| 캐시 키 | URLRequest (URL 기반) | 개발자가 정의한 키 (예: 문자열, 객체 등) |
| 데이터 지속성 | 디스크에 저장된 경우 앱 종료 후에도 유지 | 앱 종료 시 데이터 소멸 |
| 스레드 안전성 | 기본적으로 스레드 안전 | 스레드 안전 |
| 사용 예시 | HTTP 응답 캐싱, 오프라인 데이터 제공 | 이미지 캐싱, 계산 결과 캐싱 |
NSCache는 알아서 휘발하기 때문에 이미지와 같은 비용이 큰 객체를 관리하기에 용이하고,
URLCache의 경우 메모리와 디스크에 모두 저장되기에 이전 요청에 대한 응답이 디스크에 남아 있어 이전 요청을 재시도 할 필요가 없다.
URLCache에서 이미지를 관리해도 된다. 다만 그 이미지들이 쌓이고 쌓인다면? 개발자 스스로 관리를 할 필요가 생긴다.
반대로 NSCache만 사용하면 메모리가 과도하게 쌓여 시스템이 앱 자체를 꺼버릴 수 있다.
보통 NSCache를 사용할 때 CacheManager와 같은 캐시 관리 클래스로 메모리에는 NSCache로, 디스크에는 FileManager의 cachesDirectory로 캐싱하는 방법을 사용한다.
이 과정을 생략 할 수 있는게 URLCache 인거고 반대로 URLCache에는 자동 삭제가 없기에 따로 구현이 필요하다.
알아서 잘 판단하자.