PoradnikiSamouczki

Kursy walut w Swift przez URLSession

Użyj URLSession, Codable i URLComponents oraz zachowaj informację o aktualizacji kursu, aby pokazywać kursy walut w aplikacjach Swift na iOS i macOS.

8 wrz 2026 · 6 min czytania

URLSession obsługuje sieć, a Codable kontrakt JSON. Klucz trzymaj na serwerze, poza aplikacją iOS, macOS lub watchOS.

  • Zdefiniuj model: Model zachowuje rates, source, market_session i data_updated_at. Do obliczeń kwot używaj Decimal.
  • Zostaw klucz na serwerze: Aplikacja mobilna woła własny backend, który dodaje Authorization. Swift po stronie serwera może czytać klucz z otoczenia.
  • Obsłuż status i świeżość: Sprawdź status przed dekodowaniem, rozróżnij 401 i 429 oraz pokaż czas i źródło obserwacji.

Zdefiniuj model

Model zachowuje rates, source, market_session i data_updated_at. Do obliczeń kwot używaj Decimal.

swift · ExchangeRateClient.swift
import Foundationfinal class NoRedirects: NSObject, URLSessionTaskDelegate {    func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {        completionHandler(nil)    }}struct Latest: Decodable {    let base: String    let source: String    let marketSession: String    let dataUpdatedAt: String    let rates: [String: Decimal]}struct ExchangeRateClient {    let session: URLSession    let apiKey: String?    func latest(base: String) async throws -> Latest {        let normalizedBase = base.uppercased()        guard normalizedBase.count == 3, normalizedBase.allSatisfy({ $0.isASCII && $0.isLetter }) else {            throw URLError(.badURL)        }        guard var components = URLComponents(string: "https://api.exchangerate.dev/v1/latest/\(normalizedBase)") else {            throw URLError(.badURL)        }        components.queryItems = [URLQueryItem(name: "symbols", value: "EUR,GBP,JPY")]        guard let url = components.url else { throw URLError(.badURL) }        var request = URLRequest(url: url)        request.timeoutInterval = 10        if let apiKey { request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") }        let (data, response) = try await session.data(for: request)        guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {            throw URLError(.badServerResponse)        }        let decoder = JSONDecoder()        decoder.keyDecodingStrategy = .convertFromSnakeCase        return try decoder.decode(Latest.self, from: data)    }}

Zostaw klucz na serwerze

Aplikacja mobilna woła własny backend, który dodaje Authorization. Swift po stronie serwera może czytać klucz z otoczenia.

swift · server setup
let key = ProcessInfo.processInfo.environment["EXCHANGERATE_API_KEY"]let session = URLSession(configuration: .ephemeral, delegate: NoRedirects(), delegateQueue: nil)let client = ExchangeRateClient(    session: session,    apiKey: key)let latest = try await client.latest(base: "USD")print(latest.rates["EUR"] as Any, latest.source, latest.dataUpdatedAt)

Obsłuż status i świeżość

Sprawdź status przed dekodowaniem, rozróżnij 401 i 429 oraz pokaż czas i źródło obserwacji.

Zachowaj kontekst kursu

Raport dzienny potrzebuje jednego wywołania, a dashboard może działać co godzinę. Po 429 zmniejsz częstotliwość zamiast tworzyć pętlę ponowień.

  • Zapisuj kurs ze źródłem i czasem.
  • Używaj go w automatyzacji i analizie.
  • Nie traktuj go jako ceny wykonawczej.

Pytania

Czy klucz może być w iOS?

Nie, można go wyciągnąć z pakietu; użyj serwera.

Czy działa bez klucza?

Tak, w ramach anonimowego testowania.

Po co Decimal?

Aby uniknąć błędów Double przy mnożeniu i zaokrąglaniu.

Co zrobić po 429?

Zmniejsz częstotliwość, nie ponawiaj natychmiast i przestrzegaj limitu planu.

Czytaj dalej

Zacznij od bezpłatnego klucza API

5 000 zapytań miesięcznie w bezpłatnym planie. Bez karty kredytowej.

Uzyskaj bezpłatny klucz