Published on

Xcode-da FileManager-ga ma'lumot va rasmlarni saqlash

Authors

FileManager nima va nima uchun kerak

FileManager — iOS qurilmadagi fayl tizimi bilan ishlash imkonini beradi. U Mac-dagi Finder kabi ishlaydi: avval saqlamoqchi bo'lgan papkani topasiz, so'ngra faylni o'sha yerga saqlaymiz va kerak bo'lganda olamiz.

Asosiy farq: biz papkalarda qo'lda navigation qilmaymiz — bularning barchasini dasturiy ravishda kod orqali bajaramiz.

FileManager qachon ishlatiladi

VaziyatTavsiya
Kichik qiymatlar (foydalanuvchi nomi, sozlamalar)UserDefaults
Tuzilgan ma'lumotlar (entity-lar, munosabatlar)Core Data
Rasmlar, videolar, audio, JSON fayllarFileManager

Muhim: Core Data-ga to'g'ridan-to'g'ri rasm saqlash mumkin emas — buning uchun FileManager ishlatiladi.

Ehtiyot bo'lish kerak bo'lgan jihatlar

  • FileManager foydalanuvchining qurilmasiga saqlaydi
  • Saqlanganlar o'chirilgunga qadar qoladi
  • Siz, dasturchi sifatida, qayerga saqlayotganingizni doim kuzatishingiz kerak — aks holda eski fayllarni topa olmaysiz va o'chirolmaysiz

Arxitektura

Ushbu video uchun qo'llaniladigan tuzilma:

FileManagerBootcamp (View)
    └── FileManagerViewModel (ObservableObject)
            └── LocalFileManager (Singleton)
  • View — faqat UI
  • ViewModel — view-ga xos mantiq
  • LocalFileManager — ilovaning istalgan joyidan foydalaniladigan, umumiy fayl boshqarish klassi

Uchta asosiy katalog

// 1. Documents Directory
// Foydalanuvchi yaratgan, qayta tiklab bo'lmaydigan ma'lumotlar uchun
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

// 2. Caches Directory (ENG KO'P ISHLATILADIGAN)
// Internetdan yuklab olinadigan, qayta yuklanishi mumkin bo'lgan kontentlar uchun
FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)

// 3. Temp Directory
// Faqat vaqtinchalik foydalanish uchun
FileManager.default.temporaryDirectory

Apple-ning rasmiy tavsiyasiga ko'ra:

  • Documents: foydalanuvchi tomonidan yaratilgan, qayta tiklab bo'lmaydigan fayllar
  • Caches: yuklab olingan kontent (rasmlar, xaritalar, jurnallar) — qayta yuklanishi mumkin
  • Temp: faqat vaqtinchalik foydalaniladigan ma'lumotlar

LocalFileManager — singleton class

class LocalFileManager {
    static let instance = LocalFileManager()
    let folderName = "my_app_images"

    init() {
        createFolderIfNeeded()
    }
}

Papka yaratish

func createFolderIfNeeded() {
    guard let path = FileManager
        .default
        .urls(for: .cachesDirectory, in: .userDomainMask)
        .first?
        .appendingPathComponent(folderName)
        .path else { return }

    if !FileManager.default.fileExists(atPath: path) {
        do {
            try FileManager.default.createDirectory(
                atPath: path,
                withIntermediateDirectories: true,
                attributes: nil
            )
            print("Success creating folder")
        } catch let error {
            print("Error creating folder: \(error)")
        }
    }
}
  • appendingPathComponent(folderName) — caches katalogi ichiga yangi papka
  • withIntermediateDirectories: true — ichma-ich papkalar kerak bo'lsa, barchasini yaratadi
  • Papka allaqachon mavjud bo'lsa — ikki marta yaratilmaydi

URL-ni olish — getPath(for:)

Saqlash, olish va o'chirishda bir xil yo'l ishlatilishi kerak. Shu sababdan, yo'lni hisoblash mantig'ini alohida funksiyaga chiqaramiz:

func getPath(for name: String) -> URL? {
    guard let path = FileManager
        .default
        .urls(for: .cachesDirectory, in: .userDomainMask)
        .first?
        .appendingPathComponent(folderName)
        .appendingPathComponent("\(name).jpg") else {
        print("Error getting path")
        return nil
    }
    return path
}
  • .first?urls(for:in:) massiv qaytaradi, biz faqat birinchisini olamiz
  • .appendingPathComponent(folderName) — papkamizga kiramiz
  • .appendingPathComponent("\(name).jpg") — fayl nomini qo'shamiz

Rasm saqlash — saveImage(_:name:)

@discardableResult
func saveImage(image: UIImage, name: String) -> String {
    guard
        let data = image.jpegData(compressionQuality: 1.0),
        let path = getPath(for: name)
    else {
        return "Error getting data"
    }

    do {
        try data.write(to: path)
        return "Success saving"
    } catch let error {
        return "Error saving: \(error)"
    }
}
  • UIImage ishlatiladi — rasm ma'lumotlarini view-lar va klaslar orasida uzatish osonroq. Image (SwiftUI komponenti) ma'lumot sifatida ishlatish qiyin.
  • jpegData(compressionQuality:) — UIImage-ni JPEG formatiga o'giradi. PNG uchun .pngData() ishlatiladi.
  • compressionQuality: 1.0 — 100% sifat. Kamroq joy egallash uchun 0.5 ham ishlatsa bo'ladi.
  • Mavjud fayl ustiga yozilsa — qayta yoziladi (overwrite)

Rasm olish — getImage(name:)

func getImage(name: String) -> UIImage? {
    guard
        let path = getPath(for: name),
        FileManager.default.fileExists(atPath: path.path)
    else {
        print("Error getting path")
        return nil
    }

    return UIImage(contentsOfFile: path.path)
}
  • fileExists(atPath:) — fayl mavjudligini tekshiradi (path.path — URL-ni string-ga o'giradi)
  • UIImage(contentsOfFile:) — fayldan UIImage yaratadi

Rasm o'chirish — deleteImage(name:)

@discardableResult
func deleteImage(name: String) -> String {
    guard
        let path = getPath(for: name),
        FileManager.default.fileExists(atPath: path.path)
    else {
        return "Error getting path"
    }

    do {
        try FileManager.default.removeItem(at: path)
        return "Successfully deleted"
    } catch let error {
        return "Error deleting: \(error)"
    }
}
  • removeItem(at:) — URL versiyasi (string versiyasi removeItem(atPath:))
  • Fayl mavjud bo'lmasa — xatolik qaytaradi, ilovani crash qilmaydi

Papka o'chirish — deleteFolder()

Barcha saqlangan rasmlarni bir vaqtda o'chirish uchun — papkaning o'zini o'chirish:

func deleteFolder() {
    guard let path = FileManager
        .default
        .urls(for: .cachesDirectory, in: .userDomainMask)
        .first?
        .appendingPathComponent(folderName)
        .path else { return }

    do {
        try FileManager.default.removeItem(atPath: path)
        print("Success deleting folder")
    } catch let error {
        print("Error deleting folder: \(error)")
    }
}

Papka o'chirilganda, uning ichidagi barcha fayllar ham o'chadi. Ilovani keyingi ochilishida createFolderIfNeeded() papkani qayta yaratadi.


ViewModel

class FileManagerViewModel: ObservableObject {
    let manager = LocalFileManager.instance
    let imageName: String = "steve_jobs"

    @Published var image: UIImage? = nil
    @Published var infoMessage: String = ""

    init() {
        getImageFromAssetsFolder()
    }

    func getImageFromAssetsFolder() {
        image = UIImage(named: imageName)
    }

    func getImageFromFileManager() {
        image = manager.getImage(name: imageName)
    }

    func saveImage() {
        guard let image = image else { return }
        infoMessage = manager.saveImage(image: image, name: imageName)
    }

    func deleteImage() {
        infoMessage = manager.deleteImage(name: imageName)
    }
}

View

struct FileManagerBootcamp: View {
    @StateObject var vm = FileManagerViewModel()

    var body: some View {
        NavigationView {
            VStack {
                if let image = vm.image {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200, height: 200)
                        .clipped()
                        .cornerRadius(10)
                }

                HStack {
                    Button("Save to FM") {
                        vm.saveImage()
                    }
                    .foregroundColor(.white)
                    .font(.headline)
                    .padding()
                    .padding(.horizontal)
                    .background(Color.blue)
                    .cornerRadius(10)

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

                Text(vm.infoMessage)
                    .font(.largeTitle)
                    .fontWeight(.semibold)
                    .foregroundColor(.purple)

                Spacer()
            }
            .navigationTitle("File Manager")
        }
    }
}

Assets papkasi haqida eslatma

// Assets papkasidagi rasmlar — ilova binary-ga "o'rnatiladi"
// Bu App Store-dagi fayl hajmini oshiradi
// Katta/dinamik rasmlar uchun ishlatmang

// ✅ Assets uchun mos: ikonkalar, logolar, doim kerak bo'ladigan kichik rasmlar
// ❌ Assets uchun mos emas: foydalanuvchi profil rasmlari, Instagram postlari

Xulosa

FunksiyaUsul
Papka yaratishcreateDirectory(atPath:withIntermediateDirectories:attributes:)
Fayl mavjudligini tekshirishfileExists(atPath:)
Fayl saqlashdata.write(to: url)
Fayl olishUIImage(contentsOfFile: path)
Fayl o'chirishremoveItem(at: url)
Papka o'chirishremoveItem(atPath: path)

Asosiy qoida: FileManager-da saqlaganlarni o'zingiz kuzating — qayerga, qaysi nom bilan saqlaysiz, kerak bo'lganda o'sha yo'l orqali topishingiz kerak. getPath(for:) kabi yordamchi funksiyalar bu vazifani osonlashtiradi.

Buy mea coffee