Published on

SwiftUI crypto app — qayta ishlatiladigan tarmoq qatlamini yaratish

Authors

SwiftUI crypto app — qayta ishlatiladigan tarmoq qatlamini yaratish

Ushbu darsda biz oldingi darsda yozgan tarmoq kodimizni optimallashtiramiz. Loyihamizda kelajakda boshqa API so'rovlarini ham oson amalga oshirish uchun qayta ishlatiladigan (reusable) tarmoq menejeri — NetworkingManagerni yaratamiz.

Shuningdek, tarmoq xatoliklarini konsolda chiroyli emoji belgilar bilan ko'rsatadigan maxsus NetworkingError xatoliklar klassini tuzamiz.


1. NetworkingManager utility klassini yaratish

Loyihada utilities nomli yangi guruh (Folder) yaratamiz va uning ichida NetworkingManager.swift faylini ochamiz.

Ushbu klass statik funksiyalardan iborat bo'lib, ob'ekt yaratmasdan to'g'ridan-to'g'ri chaqirish imkonini beradi:

import Foundation
import Combine

class NetworkingManager {

    // Maxsus xatoliklar enumi (LocalizedError protokoli bilan)
    enum NetworkingError: LocalizedError {
        case badURLResponse(url: URL) // Noto'g'ri server javobi uchun (URL manzili bilan)
        case unknown // Noma'lum xatolik uchun

        // Konsolda ko'rinadigan xato tavsifini o'zgartiramiz
        var errorDescription: String? {
            switch self {
            case .badURLResponse(url: let url):
                return "🔥 Serverdan noto'g'ri javob keldi. URL: \(url.absoluteString)"
            case .unknown:
                return "⚠️ Noma'lum xatolik yuz berdi"
            }
        }
    }

    // Tarmoqdan ma'lumot yuklash uchun umumiy (generic) funksiya
    static func download(url: URL) -> AnyPublisher<Data, Error> {
        return URLSession.shared.dataTaskPublisher(for: url)
            // Fondagi oqimda ishga tushirish
            .subscribe(on: DispatchQueue.global(qos: .default))
            // Server javobini tekshirish uchun yordamchi funksiyani chaqiramiz
            .tryMap({ try handleURLResponse(output: $0, url: url) })
            // Natijani asosiy oqimga (Main Thread) qaytarish
            .receive(on: DispatchQueue.main)
            // Combine zanjiri turlarini yashirish va sodda AnyPublisher qaytarish
            .eraseToAnyPublisher()
    }

    // Server javobini va HTTP status kodini tekshiruvchi funksiya
    static func handleURLResponse(output: URLSession.DataTaskPublisher.Output, url: URL) throws -> Data {
        guard let response = output.response as? HTTPURLResponse,
              response.statusCode >= 200 && response.statusCode < 300 else {
            throw NetworkingError.badURLResponse(url: url)
        }
        return output.data
    }

    // Obunaning yakunlanishini (Completion) boshqaruvchi umumiy funksiya
    static func handleCompletion(completion: Subscribers.Completion<Error>) {
        switch completion {
        case .finished:
            break
        case .failure(let error):
            print(error.localizedDescription)
        }
    }
}

2. CoinDataService kodini optimallashtirish

Endi CoinDataService fayliga o'tib, yuklash kodlarini yangi yaratgan NetworkingManager yordamida ancha qisqartiramiz:

import Foundation
import Combine

class CoinDataService {

    @Published var allCoins: [CoinModel] = []
    private var coinSubscription: AnyCancellable?

    init() {
        getCoins()
    }

    private func getCoins() {
        guard let url = URL(string: "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24h") else { return }

        // NetworkingManager-dan foydalanib yuklashni amalga oshiramiz
        coinSubscription = NetworkingManager.download(url: url)
            // Decode amali faqat shu modelga tegishli bo'lgani uchun servis ichida qoladi
            .decode(type: [CoinModel].self, decoder: JSONDecoder())
            .sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: { [weak self] (returnedCoins) in
                self?.allCoins = returnedCoins
                self?.coinSubscription?.cancel()
            })
    }
}

3. Kodni ajratishning afzalliklari

Nega biz tarmoq so'rovini alohida klassga ajratdik?

  • Reusability (Qayta foydalanish): Kelajakda ilovada 5 xil API so'rovi bo'lsa ham, barchasida ayni bir NetworkingManager.download(url:) funksiyasini yozib ketishimiz mumkin. Kod qayta-qayta yozilmaydi.
  • Cleaner Code (Toza kod): Servis fayllarimiz juda sodda va faqat o'zining modelini boshqarish bilan band bo'ladi.
  • Advanced Error Handling: Xatolik yuz berganda qaysi URL muammo yaratayotganini emojilar yordamida konsolda darhol ajratib olamiz.

Keyingi darsda biz ushbu tarmoq qatlamidan foydalanib, har bir kriptovalyutaning ikonkasini (Coin Image) internetdan yuklab olishni va kesh tizimini yaratishni o'rganamiz! 🚀

Buy mea coffee