Published on

SwiftUI crypto app — rasmlarni FileManager-ga saqlash

Authors

SwiftUI crypto app — rasmlarni FileManager-ga saqlash

Ushbu darsda biz ilovamizning ishlash tezligi va internet trafigini tejashni yangi bosqichga olib chiqamiz. Hozirgi holatda tangalar ro'yxatini pastga aylantirib, so'ng yana tepaga qaytsak, SwiftUI ro'yxat elementlarini qayta chizadi va rasmlarni internetdan qaytadan yuklaydi.

Buning oldini olish uchun biz yuklangan rasmlarni qurilmaning xotirasiga (Caches papkasiga) LocalFileManager yordamida keshlab (save) qo'yamiz. Keyingi safar rasm so'ralganda, birinchi bo'lib fayllar tizimi tekshiriladi, agar u yerda rasm topilmasa, keyin internetdan yuklanadi.


1. LocalFileManager utility klassini yaratish

Loyihamizning utilities papkasi ichida LocalFileManager.swift faylini yaratamiz. Ushbu klass singleton shaklida loyihalashtiriladi:

import Foundation
import SwiftUI

class LocalFileManager {

    // Singleton ob'ekti
    static let instance = LocalFileManager()

    private init() {}

    // Rasm faylini FileManager-ga saqlash
    func saveImage(image: UIImage, imageName: String, folderName: String) {

        // Agar papka mavjud bo'lmasa, uni yaratamiz
        createFolderIfNeeded(folderName: folderName)

        // Rasm ma'lumotlarini PNG formatida olamiz
        guard
            let data = image.pngData(),
            let url = getURLForImage(imageName: imageName, folderName: folderName)
        else { return }

        // Ma'lumotni olingan URL manziliga yozamiz
        do {
            try data.write(to: url)
        } catch let error {
            print("Rasm saqlashda xatolik yuz berdi. Image: \(imageName). Error: \(error)")
        }
    }

    // Rasm faylini FileManager-dan olish
    func getImage(imageName: String, folderName: String) -> UIImage? {
        guard
            let url = getURLForImage(imageName: imageName, folderName: folderName),
            FileManager.default.fileExists(atPath: url.path) // Fayl mavjudligini tekshiramiz
        else { return nil }

        // Fayl yo'li orqali UIImage obyektini yaratib qaytaramiz
        return UIImage(contentsOfFile: url.path)
    }

    // Kerak bo'lsa yangi papka yaratish funksiyasi
    private func createFolderIfNeeded(folderName: String) {
        guard let url = getURLForFolder(folderName: folderName) else { return }

        // Papka mavjudligini tekshirib, yo'q bo'lsa yaratamiz
        if !FileManager.default.fileExists(atPath: url.path) {
            do {
                try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
            } catch let error {
                print("Papka yaratishda xatolik yuz berdi. Folder: \(folderName). Error: \(error)")
            }
        }
    }

    // Papka uchun URL manzilini olish (CachesDirectory ichida)
    private func getURLForFolder(folderName: String) -> URL? {
        guard let url = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return nil
        }
        return url.appendingPathComponent(folderName)
    }

    // Rasm fayli uchun to'liq URL manzilini olish
    private func getURLForImage(imageName: String, folderName: String) -> URL? {
        guard let folderURL = getURLForFolder(folderName: folderName) else {
            return nil
        }
        return folderURL.appendingPathComponent(imageName + ".png")
    }
}

2. CoinImageService-ni kesh tizimiga moslashtirish

Endi services/CoinImageService.swift faylini yangilaymiz. Rasm so'ralganda birinchi bo'lib fileManager tekshiriladi, agar u yerda rasm bo'lmasa, downloadCoinImage() funksiyasi chaqiriladi:

import Foundation
import SwiftUI
import Combine

class CoinImageService {

    @Published var image: UIImage? = nil

    private var imageSubscription: AnyCancellable?
    private let coin: CoinModel

    // LocalFileManager havolasi va kesh papkasi nomi
    private let fileManager = LocalFileManager.instance
    private let folderName = "coin_images"
    private let imageName: String

    init(coin: CoinModel) {
        self.coin = coin
        self.imageName = coin.id // Har bir rasm coin id-si bilan nomlanadi (masalan: "bitcoin.png")
        getCoinImage()
    }

    private func getCoinImage() {
        // Birinchi bo'lib xotirani (keshni) tekshiramiz
        if let savedImage = fileManager.getImage(imageName: imageName, folderName: folderName) {
            self.image = savedImage
        } else {
            // Agar keshda rasm yo'q bo'lsa, internetdan yuklaymiz
            downloadCoinImage()
        }
    }

    private func downloadCoinImage() {
        guard let url = URL(string: coin.image) else { return }

        imageSubscription = NetworkingManager.download(url: url)
            .tryMap({ (data) -> UIImage? in
                return UIImage(data: data)
            })
            .sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: { [weak self] (returnedImage) in
                guard let self = self, let downloadedImage = returnedImage else { return }

                // Rasmni view-ga uzatamiz
                self.image = downloadedImage
                self.imageSubscription?.cancel()

                // Yuklangan rasmni kelajak uchun keshga saqlab qo'yamiz
                self.fileManager.saveImage(image: downloadedImage, imageName: self.imageName, folderName: self.folderName)
            })
    }
}

3. Nega aynan CachesDirectory?

Ilovamizda rasmlarni saqlash uchun cachesDirectoryni tanladik. Buning muhim sabablari bor:

  • Tizim nazorati: Agar qurilma xotirasi to'lib ketsa, iOS avtomatik ravishda Caches ichidagi keraksiz keshlarni tozalaydi.
  • Xavfsizlik: Ilovamiz xotirani to'ldirib yuborishi va tizimni qotirishi oldi olinadi.
  • Qayta tiklanish: Agar kesh o'chib ketsa ham, ilovamizda internetdan qayta yuklab olish logikasi (fallback) borligi sababli rasm baribir ekranda ko'rsatiladi.

Endi ilovani ishga tushirib ro'yxatni aylantirsangiz, rasmlar juda tez va tarmoq trafigini umuman sarflamasdan yuklanadi.

Keyingi darsda biz ro'yxat tepasida qidiruv satrini (Search Bar) yaratishni va tangalarni dinamik ravishda qidirishni yo'lga qo'yamiz! 🚀

Buy mea coffee