Published on

SwiftUI ilovasida rasmlarni saqlash va keshlash (cache)

Authors

Cache (kesh) nima va nima uchun kerak

Cache — internetdan yuklab olingan ma'lumotlarni vaqtincha saqlash joyi.

Saqlash turiQachon ishlatiladi
FileManagerFoydalanuvchi har doim qayta keladigan muhim ma'lumotlar (doimiy)
CacheJoriy sessiya davomida qayta kerak bo'lishi mumkin, ammo har safar yuklamaslik kerak bo'lgan ma'lumotlar (vaqtinchalik)
Hech qanday saqlashFaqat bir marta ko'riladigan ma'lumotlar

Amaliy misol

Foydalanuvchi biror profil sahifasini ochadi → profil rasmi yuklanadi → boshqa sahifaga o'tadi → yana shu profil sahifasiga qaytadi.

  • Cache yo'q bo'lsa: rasmni internetdan qayta yuklash kerak
  • Cache bor bo'lsa: rasm allaqachon keshda — darhol ko'rsatiladi

Ilova yopilganda kesh tozalanadi — fayllar manager-dagi kabi doimiy emas.


CacheManager — NSCache bilan singleton class

class CacheManager {
    static let instance = CacheManager()
    private init() { }  // Singleton — boshqa joydan new CacheManager() qilib bo'lmaydi

    var imageCache: NSCache<NSString, UIImage> = {
        let cache = NSCache<NSString, UIImage>()
        cache.countLimit = 100          // Maksimal saqlash soni
        cache.totalCostLimit = 1024 * 1024 * 100  // Maksimal hajm (~100 MB)
        return cache
    }()
}

NSCache tushuntirish

  • NSCache<NSString, UIImage> — kalit NSString, qiymat UIImage
  • String o'rniga NSStringNSCache Objective-C-da yozilgan, Swift String-ni to'g'ridan-to'g'ri qabul qilmaydi
  • Stringni NSString-ga o'girish: name as NSString
  • Swift kompilyatori bu ikkalasini bir-biriga as orqali bemalol o'girishga ruxsat beradi

countLimit va totalCostLimit

cache.countLimit = 100
// Keshda 100 tadan ko'p element bo'lmaydi
// 101-element qo'shilganda, eski elementlar avtomatik o'chiriladi

cache.totalCostLimit = 1024 * 1024 * 100
// Keshning umumiy hajmi ~100 MB dan oshmasin
// Oshib ketsa, eski elementlar chiqarib yuboriladi

Kesh xotirada (RAM) saqlanadi — shuning uchun hajmni nazorat qilish muhim. Haddan oshib ketsa — ilova sekinlashishi yoki crash bo'lishi mumkin.

private init — to'g'ri singleton

// NOTO'G'RI: hech narsa yangi instance yaratishni to'sqinlik qilmaydi
static let instance = CacheManager()

// TO'G'RI: private init bilan faqat class ichidan init qilish mumkin
static let instance = CacheManager()
private init() { }

private init — singleton pattern-ining to'liq versiyasi. Buni har qanday singleton-ga qo'shish tavsiya etiladi.


Keshga qo'shish — add(image:name:)

@discardableResult
func add(image: UIImage, name: String) -> String {
    imageCache.setObject(image, forKey: name as NSString)
    return "Added to cache"
}
  • setObject(_:forKey:) — keshga element qo'shish
  • Agar shu kalit bilan element allaqachon bo'lsa — ustiga yoziladi

Keshdan olish — get(name:)

func get(name: String) -> UIImage? {
    return imageCache.object(forKey: name as NSString)
}
  • object(forKey:) — keshdan element olish
  • Agar topilmasa — nil qaytaradi

Keshdan o'chirish — remove(name:)

@discardableResult
func remove(name: String) -> String {
    imageCache.removeObject(forKey: name as NSString)
    return "Removed from cache"
}

CacheViewModel

class CacheViewModel: ObservableObject {
    let manager = CacheManager.instance
    let imageName: String = "steve_jobs"

    @Published var startingImage: UIImage? = nil
    @Published var cachedImage: UIImage? = nil
    @Published var infoMessage: String = ""

    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 {
            infoMessage = "Image not found in cache"
        }
    }
}

View

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("Save to cache") {
                        vm.saveToCache()
                    }
                    .foregroundColor(.white)
                    .font(.headline)
                    .padding()
                    .background(Color.blue)
                    .cornerRadius(10)

                    Button("Delete from cache") {
                        vm.removeFromCache()
                    }
                    .foregroundColor(.white)
                    .font(.headline)
                    .padding()
                    .background(Color.red)
                    .cornerRadius(10)
                }

                Button("Get from cache") {
                    vm.getFromCache()
                }
                .foregroundColor(.white)
                .font(.headline)
                .padding()
                .background(Color.green)
                .cornerRadius(10)

                if let cachedImage = vm.cachedImage {
                    Image(uiImage: cachedImage)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200, height: 200)
                        .clipped()
                        .cornerRadius(10)
                }

                Spacer()
            }
            .navigationTitle("Cache Bootcamp")
        }
    }
}

Cache vs FileManager — qaysi biri qachon

XususiyatNSCacheFileManager
Saqlash joyiRAM (xotira)Disk (fayl tizimi)
Ilova yopilgandaO'chib ketadiQoladi
TezlikJuda tezBiroz sekinroq
Hajm nazoratiAvtomatik (countLimit)Qo'lda nazorat
IshlatilishSessiya davomida qayta keladigan ma'lumotlarDoimiy saqlash kerak bo'lgan fayllar

Keshning ishlash mantig'i (amaliy)

Foydalanuvchi profil sahifasini ochadi
Cache-dan tekshirish: manager.get(name: userId)
    ├── TopildiRasmni ko'rsatish (internet kerak emas)
    └── Topilmadi
        Internetdan yuklash
        Cache-ga saqlash: manager.add(image: image, name: userId)
        Rasmni ko'rsatish

Bu — keyingi videoda ko'riladigan downloadImageFromURL funksiyasining asosi.


Xulosa

  • NSCache — Swift-ning o'rnatilgan, xotirada ishlaydigancache tizimi
  • countLimit va totalCostLimit bilan hajmni nazorat qiling
  • NSStringNSCache Objective-C-dan kelgani uchun String o'rniga NSString ishlatiladi
  • Cache — vaqtinchalik: ilova qayta ishga tushsa, tozalanadi
  • FileManager bilan birgalikda ishlatilganda — eng samarali kesh strategiyasi: avval cache-dan tekshir, yo'q bo'lsa FileManager-dan, yo'q bo'lsa internetdan yukla
Buy mea coffee