- Published on
SwiftUI crypto app — Combine yordamida tangalar rasmlarini yuklash
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
SwiftUI crypto app — Combine yordamida tangalar rasmlarini yuklash
Ushbu darsda biz ro'yxatimizdagi doira shaklidagi vaqtinchalik joylarni (placeholders) har bir tangaga mos keladigan real rasmlar (logotiplar) bilan almashtiramiz.
Buning uchun biz MVVM arxitekturasining yana bir to'liq zanjirini yaratamiz: rasmlarni yuklovchi CoinImageService, uni boshqaruvchi CoinImageViewModel va ekranda ko'rsatuvchi CoinImageView reusable (qayta ishlatiladigan) komponentini tuzamiz.
1. CoinImageService klassini yaratish
services papkasi ichida CoinImageService.swift faylini yaratamiz. Bu klass faqat bitta tanga modelini qabul qiladi va unga tegishli rasm URL manzilidan rasm ma'lumotlarini yuklaydi:
import Foundation
import SwiftUI
import Combine
class CoinImageService {
// Yuklangan rasmni saqlovchi publisher
@Published var image: UIImage? = nil
private var imageSubscription: AnyCancellable?
private let coin: CoinModel
init(coin: CoinModel) {
self.coin = coin
getCoinImage()
}
private func getCoinImage() {
// Tanganing rasm URL manzilini tekshiramiz
guard let url = URL(string: coin.image) else { return }
// NetworkingManager-ning download funksiyasini chaqiramiz
imageSubscription = NetworkingManager.download(url: url)
// Yuklangan Data-ni UIImage formatiga o'tkazamiz
.tryMap({ (data) -> UIImage? in
return UIImage(data: data)
})
// Natijani asosiy oqimda qabul qilamiz
.sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: { [weak self] (returnedImage) in
// Rasmni o'zgaruvchiga saqlaymiz va obunani yopamiz
self?.image = returnedImage
self?.imageSubscription?.cancel()
})
}
}
2. CoinImageViewModel yaratish
components/CoinImage papkasi ichida CoinImageViewModel.swift faylini yaratamiz. U yuklanish holatini va servisdan olingan rasmni boshqaradi:
import Foundation
import SwiftUI
import Combine
class CoinImageViewModel: ObservableObject {
@Published var image: UIImage? = nil
@Published var isLoading: Bool = false
private let coin: CoinModel
private let dataService: CoinImageService
private var cancelables = Set<AnyCancellable>()
init(coin: CoinModel) {
self.coin = coin
// Har bir tanga uchun alohida rasm xizmatini ishga tushiramiz
self.dataService = CoinImageService(coin: coin)
self.isLoading = true
addSubscribers()
}
private func addSubscribers() {
// Servisdagi image publisher-ga obuna bo'lamiz
dataService.$image
.sink { [weak self] (_) in
// Rasm yuklanib bo'lingach, yuklanish holatini yakunlaymiz
self?.isLoading = false
} receiveValue: { [weak self] (returnedImage) in
// Qabul qilingan rasmni ViewModel-dagi nashr etiluvchi image-ga bog'laymiz
self?.image = returnedImage
}
.store(in: &cancelables)
}
}
3. CoinImageView reusable komponentini yaratish
components/CoinImage papkasida CoinImageView.swift faylini yaratamiz. Swift-da @StateObject o'zgaruvchisini initializer (init) orqali to'g'ri bog'lash uchun _vm (tag chiziqli variant) orqali ViewModel-ni bog'laymiz:
import SwiftUI
struct CoinImageView: View {
// ViewModel-ni StateObject sifatida init ichida bog'laymiz
@StateObject var vm: CoinImageViewModel
init(coin: CoinModel) {
// _vm orqali StateObject-ni o'rab turgan o'zgaruvchini (wrapper) o'zimiz yaratamiz
_vm = StateObject(wrappedValue: CoinImageViewModel(coin: coin))
}
var body: some View {
ZStack {
if let image = vm.image {
// Rasm muvaffaqiyatli yuklansa ko'rsatamiz
Image(uiImage: image)
.resizable()
.scaledToFit()
} else if vm.isLoading {
// Rasm hali yuklanayotgan bo'lsa
ProgressView()
} else {
// Rasm yuklashda xatolik bo'lsa, savol belgisi chiqadi
Image(systemName: "questionmark")
.foregroundColor(Color.theme.secondaryText)
}
}
}
}
struct CoinImageView_Previews: PreviewProvider {
static var previews: some View {
CoinImageView(coin: dev.coin)
.padding()
.previewLayout(.sizeThatFits)
}
}
4. CoinRowView-ga integratsiya qilish
Endi views/CoinRowView.swift fayliga o'tamiz va undagi vaqtinchalik doira belgisini (Circle()) yangi yaratgan CoinImageView bilan almashtiramiz:
// CoinRowView.swift kengaytmasi (Extension) ichida:
private var leftColumn: some View {
HStack(spacing: 0) {
Text("\(coin.rank)")
.font(.caption)
.foregroundColor(Color.theme.secondaryText)
.frame(width: 30)
// Vaqtinchalik Circle o'rniga CoinImageView qo'yamiz
CoinImageView(coin: coin)
.frame(width: 30, height: 30)
Text(coin.symbol.uppercased())
.font(.headline)
.padding(.leading, 6)
.foregroundColor(Color.theme.accent)
}
}
Loyihani yuklab ishga tushirsak (yoki HomeView Canvas-ni yuklasak), endi barcha tangalarning real logotiplari API-dan yuklanib chiroyli ko'rsatiladi.
Keyingi darsda biz ushbu rasmlarni har safar internetdan qayta yuklab internet trafigini sarflamaslik uchun ularni telefon xotirasiga (FileManager) keshlab qo'yishni o'rganamiz! 🚀