- Published on
SwiftUI crypto app — yangilangan API ma'lumotlarini ro'yxatga yuklash
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
SwiftUI crypto app — yangilangan API ma'lumotlarini ro'yxatga yuklash
Bu darsda ikkita muhim narsa qo'shamiz:
- Portfel qiymatini va uning 24 soatlik foiz o'zgarishini haqiqiy hisoblaymiz
- Yangilash tugmasini qo'shamiz — bosilganda API dan yangi narxlar yuklab olinadi
1. Portfel qiymatini hisoblab statistikaga qo'shish
HomeViewModel-dagi mapGlobalMarketData funksiyasiga portfel tangalarini ham uzatamiz. Buning uchun subscriberga $portfolioCoins ni ham qo'shamiz:
// Eski:
marketDataService.$marketData
.map(mapGlobalMarketData)
// Yangi: market data + portfolio coinsni birlashtirish
marketDataService.$marketData
.combineLatest($portfolioCoins)
.map(mapGlobalMarketData)
.sink { [weak self] stats in
self?.statistics = stats
}
.store(in: &cancellables)
Funksiya imzosini yangilaymiz:
private func mapGlobalMarketData(
data: MarketDataModel?,
portfolioCoins: [CoinModel]
) -> [StatisticModel] {
var stats: [StatisticModel] = []
guard let data = data else { return stats }
// Portfelning joriy umumiy qiymati (har bir tanganing holdings × narxi)
let portfolioValue = portfolioCoins
.map { $0.currentHoldingsValue }
.reduce(0, +)
// Portfelning 24 soat oldingi qiymati (formulasi orqali hisoblaymiz)
let previousValue = portfolioCoins.map { coin -> Double in
let currentValue = coin.currentHoldingsValue
// API dan kelgan foiz o'zgarishi butun son (masalan 25 = 25%), uni kasrga aylantiramiz
let percentChange = (coin.priceChangePercentage24H ?? 0) / 100
// Formulasi: joriy_qiymat / (1 + foiz_o'zgarishi) = oldingi qiymat
return currentValue / (1 + percentChange)
}.reduce(0, +)
// Foiz o'zgarishi: (yangi - eski) / eski × 100
let percentageChange = ((portfolioValue - previousValue) / previousValue) * 100
let portfolio = StatisticModel(
title: "Portfel qiymati",
value: portfolioValue.asCurrencyWith2Decimals(),
percentageChange: percentageChange
)
stats.append(contentsOf: [
StatisticModel(
title: "Bozor kapitalizatsiyasi",
value: data.marketCap,
percentageChange: data.marketCapChangePercentage24HUsd
),
StatisticModel(title: "24 soatlik hajm", value: data.volume),
StatisticModel(title: "BTC ulushi", value: data.btcDominance),
portfolio
])
return stats
}
Formulaning mantig'i: Agar tanga narxi 10% oshgan bo'lsa va joriy qiymat 110. Foiz o'zgarishi: (110 - 100) / 100 × 100 = 10%.
2. Portfel qiymatini sinash
Simulatorda portfelga tanga qo'shing (masalan 0.5 ETH). Portfel qiymati statistikada ko'rinadi:
- Qiymat:
$1,900.00 - Foiz: qizil yoki yashil uchburchak bilan ko'rsatiladi
Yangi tanga qo'shgach — statistika avtomatik yangilanadi, chunki portfolioCoins publisher-ga ulanib ketgan.
3. Yangilash tugmasi (Reload Button)
HomeView-da ustun sarlavhalari (columnTitles) yaniga yangilash tugmasi qo'shamiz:
private var columnTitles: some View {
HStack {
Text("Tanga")
Spacer()
if showPortfolio {
Text("Hisoblar")
}
Text("Narx")
.frame(width: UIScreen.main.bounds.width / 3.5, alignment: .trailing)
// Yangilash tugmasi — faqat portfel ekranida emas, asosiy ekranda
Button {
withAnimation(.linear(duration: 2.0)) {
vm.reloadData()
}
} label: {
Image(systemName: "goforward")
}
// Yuklanayotganda 360° aylanadi
.rotationEffect(
Angle(degrees: vm.isLoading ? 360 : 0),
anchor: .center
)
}
.font(.caption)
.foregroundColor(Color.theme.secondaryText)
.padding(.horizontal)
}
4. isLoading holati va reloadData funksiyasi
HomeViewModel-ga yangi holatlar qo'shamiz:
@Published var isLoading: Bool = false
func reloadData() {
isLoading = true
coinDataService.getCoins() // Tangalar narxlarini qayta yuklaymiz
marketDataService.getData() // Bozor ma'lumotlarini qayta yuklaymiz
HapticManager.notification(type: .success) // Qurilma titraydi
}
isLoading-ni false-ga qaytarish — statistika subscriber-da bo'ladi:
marketDataService.$marketData
.combineLatest($portfolioCoins)
.map(mapGlobalMarketData)
.sink { [weak self] stats in
self?.statistics = stats
self?.isLoading = false // Statistika yangilangach — yuklash tugadi
}
.store(in: &cancellables)
CoinDataService-dagi getCoins() va MarketDataService-dagi getData() funksiyalarini private-dan internal (yoki ochiq) qilamiz — boshqa yerdan chaqirish uchun.
5. HapticManager — taktil tebranish
utilities papkasida HapticManager.swift faylini yaratamiz:
import Foundation
import UIKit
class HapticManager {
// Static generator — har doim tayyor turadi
private static let generator = UINotificationFeedbackGenerator()
// Yangilash bosilganda qurilmani titratamiz
static func notification(type: UINotificationFeedbackGenerator.FeedbackType) {
generator.notificationOccurred(type)
}
}
Chaqirish:
HapticManager.notification(type: .success) // muvaffaqiyatli
HapticManager.notification(type: .error) // xatolik
HapticManager.notification(type: .warning) // ogohlantirish
Eslatma: Simulatorda tebranish sezilmaydi. Haqiqiy qurilmada yangilash tugmasini bosganingizda telefon yengil titrashini sezasiz.
Xulosa
Bu darsda juda ko'p mantiq qo'shdik:
- Portfel qiymati va foizi endi haqiqiy hisoblanadi
- Yangilash tugmasi bosilganda API ga yangi so'rov yuboriladi
- Qurilmada taktil fikr-bildirish (haptic) bor
- Barcha publisher-subscriber zanjiri sinxron ishlaydi
"Butun ilovamiz bitta go'zal publisher-subscriber tizimi bilan yashaydi. Bir joyda narx yangilansa — portfel, statistika, ko'rsatgichlar — hammasi o'zi yangilanadi. Bu iOS dasturlashning kelajagi!"
Keyingi darsda biz ro'yxatni saralash (sorting) va animatsiyalarni qo'shamiz. 🚀