مقدمة: لماذا من المهم إتقان العمل مع HTTP بلغة Swift
\nتطبيقات الهواتف المحمولة وأجهزة الكمبيوتر المكتبية الحديثة نادراً ما توجد بمعزل عن غيرها. أي تطبيق تقريباً - من أداة الطقس إلى التطبيق البنكي - يتبادل البيانات مع الخادم. لهذا الغرض، يُستخدم بروتوكول HTTP، وعلى جانب Swift (iOS/macOS) الأداة الرئيسية هي إطار العمل Foundation وفئته URLSession.
في هذه المقالة، سنشرح كيفية إنشاء عميل HTTP بلغة Swift بشكل صحيح: من طلب GET بسيط إلى معالجة الأخطاء المعقدة والعمل مع JSON. ستكون المادة مفيدة لكل من المبتدئين الذين يتعرفون على تطوير iOS، والمطورين ذوي الخبرة الذين يرغبون في تنظيم معرفتهم.
\nسننظر في النهج الحديث باستخدام async/await (Swift 5.5+)، مما يجعل الكود نظيفاً وقابلاً للقراءة، وسنتطرق أيضاً إلى الطرق التقليدية مع الإغلاقات (completion handlers) للتوافق مع الإصدارات السابقة.
أساسيات URLSession: الإنشاء والتكوين
\nالفئة URLSession هي "قائد الأوركسترا" الرئيسي لطلبات الشبكة في Swift. وهي تدير الاتصالات والتخزين المؤقت والمصادقة. قبل إجراء الطلبات، تحتاج إلى إنشاء مثيل للجلسة.
أنواع الجلسات
\n- \n
- مشتركة (مفردة):
URLSession.shared- جلسة بسيطة بدون تخصيص. مناسبة للطلبات الأساسية. \n - افتراضية:
URLSession(configuration: .default)- تسمح بتكوين مهلات الاتصال وذاكرة التخزين المؤقت والرؤوس. \n - مؤقتة:
URLSession(configuration: .ephemeral)- لا تحفظ ذاكرة التخزين المؤقت وملفات تعريف الارتباط على القرص. مثالية للبيانات الخاصة. \n - خلفية:
URLSession(configuration: .background(withIdentifier:))- للتحميل/الإرسال في الخلفية، حتى عندما يكون التطبيق مصغراً. \n
import Foundation\n\n// جلسة بسيطة\nlet sharedSession = URLSession.shared\n\n// جلسة مخصصة بمهلة 30 ثانية\nlet config = URLSessionConfiguration.default\nconfig.timeoutIntervalForRequest = 30\nconfig.timeoutIntervalForResource = 60\nlet customSession = URLSession(configuration: config)\n\n\nإنشاء وإرسال طلبات HTTP
\nيتم تشكيل الطلب باستخدام الفئة URLRequest. تحتوي على عنوان URL وطريقة HTTP والرؤوس ونص الطلب. سننظر في الطرق الرئيسية: GET و POST.
طلب GET باستخدام async/await (النهج الحديث)
\nبدءاً من Swift 5.5، أضافت Apple دعم الدوال غير المتزامنة (async/await). هذه هي الطريقة الأكثر إيجازاً وأماناً للعمل مع الشبكة.
func fetchData(from urlString: String) async throws -> Data {\n guard let url = URL(string: urlString) else {\n throw URLError(.badURL)\n }\n \n var request = URLRequest(url: url)\n request.httpMethod = "GET"\n request.setValue("application/json", forHTTPHeaderField: "Accept")\n \n let (data, response) = try await URLSession.shared.data(for: request)\n \n // التحقق من حالة HTTP\n guard let httpResponse = response as? HTTPURLResponse,\n (200...299).contains(httpResponse.statusCode) else {\n throw URLError(.badServerResponse)\n }\n \n return data\n}\n\n// الاستخدام:\nTask {\n do {\n let data = try await fetchData(from: "https://api.example.com/users")\n print("تم استلام \\(data.count) بايت")\n } catch {\n print("خطأ: \\(error.localizedDescription)")\n }\n}\n\n\nطلب POST مع نص JSON
\nلإرسال البيانات إلى الخادم، تُستخدم طريقة POST. عادةً ما يتم ترميز نص الطلب بتنسيق JSON.
\n\nstruct User: Codable {\n let name: String\n let email: String\n}\n\nfunc createUser(_ user: User) async throws -> Data {\n let url = URL(string: "https://api.example.com/users")!\n var request = URLRequest(url: url)\n request.httpMethod = "POST"\n request.setValue("application