تحديد معدل الطلبات في Swift: دليل شامل لتطبيقات iOS و macOS
\n\nتحديد معدل الطلبات (Rate limiting) هو آلية بالغة الأهمية لضمان استقرار عمل تطبيقات الهواتف المحمولة وأجهزة الكمبيوتر المكتبية. في نظام Swift البيئي (iOS/macOS)، يسمح هذا الأسلوب بالتحكم في عدد استدعاءات API، وعمليات الإدخال/الإخراج، أو أي إجراءات متكررة في وحدة زمنية. بدون تحديد معدل الطلبات، قد يتعرض تطبيقك لخطر الحظر من قبل الخادم، أو استنزاف طاقة البطارية في إعادة المحاولات اللانهائية، أو إنشاء حمل زائد على الشبكة.
\n\nلماذا نحتاج إلى الحد من تكرار الطلبات في Swift؟
\n\n- \n
- الحماية من تجاوز حدود API — تفرض العديد من الخوادم (مثل GitHub، Twitter، Stripe) حصصًا صارمة على عدد الطلبات في الدقيقة/الساعة. \n
- تحسين الأداء — منع "عاصفة" الاستدعاءات عند التمرير السريع أو الرسوم المتحركة. \n
- توفير البيانات والبطارية — خاصةً بالنسبة للأجهزة المحمولة. \n
- الامتثال لسياسات App Store — قد تؤدي الطلبات الخلفية المفرطة إلى رفض التطبيق. \n
الأساليب الأساسية لتطبيق تحديد معدل الطلبات في Swift
\n\nدعنا نستعرض ثلاثة أنماط أساسية يمكن تنفيذها دون الحاجة إلى مكتبات خارجية:
\n\n1. دلو الرموز (Token Bucket)
\nخوارزمية كلاسيكية حيث تتم إضافة "الرموز" بمعدل ثابت. يستهلك كل طلب رمزًا واحدًا. إذا نفدت الرموز، يتم رفض الطلب.
\n\nimport Foundation\n\nfinal class TokenBucket {\n private let capacity: Int\n private var tokens: Int\n private let refillRate: Double // رمز في الثانية\n private var lastRefill: Date\n private let queue = DispatchQueue(label: "token.bucket.queue")\n \n init(capacity: Int, refillRate: Double) {\n self.capacity = capacity\n self.tokens = capacity\n self.refillRate = refillRate\n self.lastRefill = Date()\n }\n \n func tryConsume() -> Bool {\n queue.sync {\n refill()\n if tokens > 0 {\n tokens -= 1\n return true\n }\n return false\n }\n }\n \n private func refill() {\n let now = Date()\n let elapsed = now.timeIntervalSince(lastRefill)\n let newTokens = Int(elapsed * refillRate)\n if newTokens > 0 {\n tokens = min(capacity, tokens + newTokens)\n lastRefill = now\n }\n }\n}\n\n// مثال على الاستخدام\nlet limiter = TokenBucket(capacity: 10, refillRate: 2.0) // 10 طلبات، 2 في الثانية\nif limiter.tryConsume() {\n print("✅ الطلب مسموح به")\n} else {\n print("⛔️ تم تجاوز الحد، انتظر")\n}\n\n2. خوارزمية النافذة المنزلقة (Sliding Window)
\nيتذكر الطوابع الزمنية لآخر N من الطلبات الناجحة. إذا كانت النافذة ممتلئة، يتم حظر الاستدعاءات الجديدة.
\n\nfinal class SlidingWindowLimiter {\n private let maxRequests: Int\n private let windowDuration: TimeInterval\n private var timestamps: [Date] = []\n private let queue = DispatchQueue(label: "sliding.window.queue")\n \n init(maxRequests: Int, windowDuration: TimeInterval = 60) {\n self.maxRequests = maxRequests\n self.windowDuration = windowDuration\n }\n \n func canProceed() -> Bool {\n queue.sync {\n let now = Date()\n // إزالة الطوابع الزمنية القديمة\n timestamps.removeAll { now.timeIntervalSince($0) > windowDuration }\n \n if timestamps.count < maxRequests {\n timestamps.append(now)\n return true\n }\n return false\n }\n }\n}\n\n// مثال: لا يزيد عن 5 طلبات في 10 ثوانٍ\nlet windowLimiter = SlidingWindowLimiter(maxRequests: 5, windowDuration: 10)\n\n3. الخنق (Throttling) باستخدام DispatchQueue
\nيستخدم آليات GCD المدمجة لتأخير إجباري