- Published on
SwiftUI crypto app — Core Data yordamida portfelni saqlash
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
SwiftUI crypto app — Core Data yordamida portfelni saqlash
Oldingi darsda portfelni tahrirlash ekranini yaratdik, lekin saqlash logikasi yo'q edi. Bu darsda biz Core Data yordamida foydalanuvchi portfelini doimiy xotiraga saqlaymiz — ilova o'chirib ochilganda ham ma'lumotlar saqlanib qoladi.
1. Core Data Entity yaratish
Xcode-da models papkasida yangi fayl yaratamiz — bu safar tur sifatida Data Model (Core Data bo'limi) tanlaymiz:
Fayl nomi: PortfolioContainer
Ichida bitta entity qo'shamiz:
| Entity nomi | Maydon | Tur |
|---|---|---|
PortfolioEntity | coinId | String |
amount | Double |
Nima uchun faqat id va amount? Ilovani ochganda tanga ma'lumotlari (narx, rasm va boshqalar) API dan qayta yuklab olinadi. Core Data-da faqat qaysi tangadan qancha borligini saqlash yetarli — qolgan ma'lumotlar har doim yangilanib turadi.
2. PortfolioDataService klassi
services papkasida PortfolioDataService.swift faylini yaratamiz:
import Foundation
import CoreData
class PortfolioDataService {
private let container: NSPersistentContainer
private let containerName: String = "PortfolioContainer"
private let entityName: String = "PortfolioEntity"
@Published var savedEntities: [PortfolioEntity] = []
init() {
container = NSPersistentContainer(name: containerName)
container.loadPersistentStores { _, error in
if let error = error {
print("Core Data yuklanmadi: \(error)")
}
}
getPortfolio() // Ilova ishga tushganda saqlangan ma'lumotlarni olamiz
}
// MARK: - Public funksiya
// Tashqaridan faqat shu funksiya chaqiriladi
func updatePortfolio(coin: CoinModel, amount: Double) {
// Bu tanga allaqachon portfelda bormi?
if let entity = savedEntities.first(where: { $0.coinId == coin.id }) {
if amount > 0 {
update(entity: entity, amount: amount) // Miqdorni yangilash
} else {
delete(entity: entity) // Miqdor 0 bo'lsa — o'chirish
}
} else {
add(coin: coin, amount: amount) // Yangi tanga qo'shish
}
}
// MARK: - Private funksiyalar
private func getPortfolio() {
let request = NSFetchRequest<PortfolioEntity>(entityName: entityName)
do {
savedEntities = try container.viewContext.fetch(request)
} catch {
print("Portfolio entitylarini olishda xato: \(error)")
}
}
private func add(coin: CoinModel, amount: Double) {
let entity = PortfolioEntity(context: container.viewContext)
entity.coinId = coin.id
entity.amount = amount
applyChanges()
}
private func update(entity: PortfolioEntity, amount: Double) {
entity.amount = amount
applyChanges()
}
private func delete(entity: PortfolioEntity) {
container.viewContext.delete(entity)
applyChanges()
}
private func save() {
do {
try container.viewContext.save()
} catch {
print("Core Data ga saqlashda xato: \(error)")
}
}
// Saqlash + portfolio ro'yxatini qayta yuklab olish
private func applyChanges() {
save()
getPortfolio() // Har safar saqlangach — to'liq qayta o'qish
}
}
Nima uchun har safar
getPortfolio()chaqiramiz? Core Data-dan to'liq qayta o'qish,savedEntities-ni har doim haqiqiy holat bilan sinxronlashtirib turadi. Bu kichik portfel uchun eng xavfsiz usul.
3. HomeViewModel-ga qo'shish
HomeViewModel.swift-da yangi servis va subscriber:
private let portfolioDataService = PortfolioDataService()
// addSubscribers() ichida yangi subscriber:
func addSubscribers() {
// ...oldingi subscriberlar...
// Portfolio subscriber: allCoins + savedEntities -> portfolioCoins
$allCoins
.combineLatest(portfolioDataService.$savedEntities)
.map(mapAllCoinsToPortfolioCoins)
.sink { [weak self] returnedCoins in
self?.portfolioCoins = returnedCoins
}
.store(in: &cancellables)
}
// allCoins va savedEntities dan portfolioCoins hosil qilish
private func mapAllCoinsToPortfolioCoins(
allCoins: [CoinModel],
portfolioEntities: [PortfolioEntity]
) -> [CoinModel] {
allCoins.compactMap { coin in
// Bu tanga portfelda bormi?
guard let entity = portfolioEntities.first(where: { $0.coinId == coin.id }) else {
return nil // compactMap nil-ni olib tashlaydi
}
// Portfeldagi miqdorni tangging currentHoldings-iga qo'yamiz
return coin.updateHoldings(amount: entity.amount)
}
}
4. PortfolioView-dan updatePortfolio chaqirish
saveButtonPressed() funksiyasini yangilaymiz:
private func saveButtonPressed() {
guard
let coin = selectedCoin,
let amount = Double(quantityText) // String -> Double
else { return }
// HomeViewModel orqali Core Data ga yozamiz
vm.updatePortfolio(coin: coin, amount: amount)
withAnimation(.easeIn) {
showCheckmark = true
removeSelectedCoin()
}
UIApplication.shared.endEditing()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation(.easeOut) {
self.showCheckmark = false
}
}
}
HomeViewModel-da updatePortfolio funksiyasi:
func updatePortfolio(coin: CoinModel, amount: Double) {
portfolioDataService.updatePortfolio(coin: coin, amount: amount)
}
5. Tanga bosilganda mavjud miqdorni ko'rsatish
Foydalanuvchi allaqachon portfelida tanga borligini bilishi uchun — uni bosganda text field-ga mavjud miqdor yozilishi kerak:
private func updateSelectedCoin(coin: CoinModel) {
selectedCoin = coin
// Bu tanga portfelda bormi?
if let portfolioCoin = vm.portfolioCoins.first(where: { $0.id == coin.id }),
let amount = portfolioCoin.currentHoldings {
// Portfeldagi miqdorni text field-ga joylashtiramiz
quantityText = "\(amount)"
} else {
quantityText = ""
}
}
Tap gestureda:
.onTapGesture {
withAnimation(.easeIn) {
updateSelectedCoin(coin: coin) // selectedCoin = coin o'rniga
}
}
6. Portfel view-da portfolio tangalarini avval ko'rsatish
Qidiruv bo'sh bo'lganda — portfelidagi tangalarni, qidirayotganda — barcha tangalarni ko'rsatamiz:
ForEach(vm.searchText.isEmpty ? vm.portfolioCoins : vm.allCoins) { coin in
CoinLogoView(coin: coin)
.frame(width: 75)
// ...
}
Natija
Ilovada test qiling:
- Tanga tanlang → miqdor kiriting → SAQLASH bosing
- Xmark bilan yoping → portfel tabida tanga paydo bo'ldi!
- Ilovani yoping va qayta oching → portfel saqlanib qoldi ✅
"Bir satr kod (
vm.updatePortfolio(coin:amount:)) bilan butun Core Data logikasi ishga tushadi. View-da logika yo'q — hamma narsa xizmatlar va ViewModel-da. Bu MVVM arxitekturasining chinakam kuchi!"
Keyingi darsda biz portfel qiymatini statistika bo'limida to'g'ri hisoblash va API ma'lumotlarini yangilash tugmasini yaratamiz. 🚀