임시로 저장하는 곳 캐시!
이미지 아무거나 하나 Assets에 넣어주고
바로 전에 했던 FileManager랑 거의 흡사한 플로우임
ViewModel 만들고
뷰모델에 있는 이미지 뷰에서 넣어주기
CacheManager를 만들어주는데 전 시간에 안한 게 있다!!
instance를 전역으로 생성할 때
딱 하나만 만들어서 써야되는데 지금처럼 되어 있으면
인스턴스 이외에도 CacheManager() 같은 방법으로 언제든 객체를 만들 수 있잖음
그거 방지해보자
쉬움. private init() { }
으로 바꿔주면 초기화 외부에서 못함!!
초기화 안되죠~ 오케이!! 싱글톤 사용할땐 init을 priavate으로 바꿔준다!
이제 이미지캐시를 만들어봅시다
NSCache를 넣어줄 때 어떤 타입을 넣어줄 건지 제네릭으로 선언해야함
그래서 <AnyObject, AnyObject>의 타입이 필요한데
키랑 밸류라고 생각하면 편할듯
키로는 NSString을 밸류로는 UIImage넣어줄겨
그리고 imageCache변수를 computed 프로퍼티로 만들어주자
cache를 만들고, .countLimit은 갯수
.totalCostLimit은 용량을 정해주는거
🤔지금 살짝 이해 안되는 부분이 컴퓨티드 프로퍼티 제일 마지막에 ()괄호를 붙여준 부분 이해안됨
add메소드를 작성하는데 UIImage와 String을 받아서 imageCache에 set해주는 로직이다!
remove는 name만 받아서 캐시에 removeObject로 키값 넣어주면 되고!
get은 이름 가지고 object를 반환해주면 됨
뷰모델로 돌아와서
save랑 remove 메소드 만들어주고
getFromCache라는 메소드도 만들어주려는데 image를 담아둘 변수가 없음
새로 만들어주자
뷰에서 버튼 하나 더 늘리고
버튼 아래로 캐시에서 이미지 가져온 뷰를 그릴예정
캔버스에서 바로 해보면 잘되는 걸 볼 수 있음
infoMessage를 만들어서 텍스트로도 확인해보자
전시간에 해줬던것처럼 add메소드나 remove 메소드가 String값을 반환하게 해주고
Text뷰에다가 넣어주자
한 가지 다른 건 UIImage?를 반환하는 메소드는
뷰모델에서 이렇게 작성해줌
class CacheManager {
static let instance = CacheManager() // Singleton
private init() { }
var imageCache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 1024 * 1024 * 100 // 100mb
return cache
}()
func add(image: UIImage, name: String) -> String {
imageCache.setObject(image, forKey: name as NSString)
return "Added to cache!"
}
func remove(name: String) -> String {
imageCache.removeObject(forKey: name as NSString)
return "removed from cache!"
}
func get(name: String) -> UIImage? {
return imageCache.object(forKey: name as NSString)
}
}
class CacheViewModel: ObservableObject {
@Published var startingImage: UIImage? = nil
@Published var cachedImage: UIImage? = nil
@Published var infoMessage: String = ""
let imageName = "steve-jobs"
let manager = CacheManager.instance
init() {
getImageFromAssetsFolder()
}
func getImageFromAssetsFolder() {
startingImage = UIImage(named: imageName)
}
func saveToCache() {
guard let image = startingImage else {return}
infoMessage = manager.add(image: image, name: imageName)
}
func removeFromCache() {
infoMessage = manager.remove(name: imageName)
}
func getFromCache() {
if let returnedImage = manager.get(name: imageName) {
cachedImage = returnedImage
infoMessage = "Got Image from Cache"
} else {
cachedImage = nil
infoMessage = "Image not found in Cache"
}
}
}
struct CacheBootcamp: View {
@StateObject var vm = CacheViewModel()
var body: some View {
NavigationView {
VStack {
if let image = vm.startingImage {
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.clipped()
.cornerRadius(10)
}
Text(vm.infoMessage)
.font(.headline)
.foregroundColor(.purple)
HStack {
Button {
vm.saveToCache()
} label: {
Text("Save to Cache")
.font(.headline)
.foregroundColor(.white)
.padding()
.background { Color.blue }
.cornerRadius(10)
}
Button {
vm.removeFromCache()
} label: {
Text("Delete from Cache")
.font(.headline)
.foregroundColor(.white)
.padding()
.background { Color.red }
.cornerRadius(10)
}
}
Button {
vm.getFromCache()
} label: {
Text("Get from Cache")
.font(.headline)
.foregroundColor(.white)
.padding()
.background { Color.green }
.cornerRadius(10)
}
if let image = vm.cachedImage {
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.clipped()
.cornerRadius(10)
}
Spacer()
}
.navigationTitle("Cache Bootcamp")
}
}
}