Tutorial/بداية سريعة مع Swift

جلب أسعار الصرف في Swift باستخدام URLSession

أنشئ عميلاً بـ URLSession وCodable وURLComponents مع نموذج واضح لحداثة السعر.

ERexchangerate.dev·Sep 8, 2026·قراءة خلال 6 دقائق

استخدم URLSession للشبكة وCodable لعقد JSON. احتفظ بالمفتاح على الخادم ولا تضعه داخل تطبيق iOS أو macOS أو watchOS.

Key points
عرّف نموذج الاستجابة: احتفظ بـ rates وsource وmarket_session وdata_updated_at في النموذج، واستخدم Decimal للحسابات المالية.
أبقِ المفتاح على الخادم: يستدعي تطبيق الهاتف خادمك، ويضيف الخادم Authorization. أما Swift على الخادم فيقرأ المفتاح من البيئة.
عالج الحالة والحداثة: افحص حالة HTTP قبل فك JSON. فرّق بين 401 و429 واعرض وقت الملاحظة ومصدرها.

عرّف نموذج الاستجابة

احتفظ بـ rates وsource وmarket_session وdata_updated_at في النموذج، واستخدم Decimal للحسابات المالية.

swift · ExchangeRateClient.swiftcopy
import Foundation

final 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)
    }
}

أبقِ المفتاح على الخادم

يستدعي تطبيق الهاتف خادمك، ويضيف الخادم Authorization. أما Swift على الخادم فيقرأ المفتاح من البيئة.

swift · server setupcopy
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)

عالج الحالة والحداثة

افحص حالة HTTP قبل فك JSON. فرّق بين 401 و429 واعرض وقت الملاحظة ومصدرها.

احفظ سياق السعر
استخدم استدعاءً يومياً للتقارير أو كل ساعة للوحة تشغيلية. عند 429 خفّض الجدول ولا تنشئ حلقة إعادة محاولة فورية.
  • احفظ السعر مع المصدر والوقت.
  • استخدمه للأتمتة والتقدير والتحليل.
  • لا تتعامل معه كسعر قابل للتنفيذ.
ER
exchangerate.dev
أدلة تكامل للمطورين.

تابع القراءة

Referenceالبدء السريع لواجهة الأسعاراقرأ TutorialJavaScript / Node.jsاقرأ Guideاحفظ سياق السعراقرأ
المزيد من المقارناتFixer vs exchangerate.devOpen Exchange Rates vs exchangerate.devCurrencylayer vs exchangerate.dev
تعلّمReading source and market_session in your pipelineIndicative vs executable FX rates: what a rates API actually gives youأسعار الصرف المرجعية للبنك المركزي الأوروبي، موضحة
أسعار مباشرةEUR/USDGBP/USDUSD/JPY