Rate Limiting en Swift: Guía completa para aplicaciones iOS y macOS
\n\nRate limiting (limitación de frecuencia de solicitudes) es un mecanismo críticamente importante para el funcionamiento estable de aplicaciones móviles y de escritorio. En el ecosistema Swift (iOS/macOS), este enfoque permite controlar la cantidad de llamadas a API, operaciones de entrada/salida o cualquier acción repetitiva por unidad de tiempo. Sin rate limiting, su aplicación corre el riesgo de ser bloqueada por el servidor, agotar la batería con reintentos infinitos o crear una carga excesiva en la red.
\n\n¿Por qué es necesaria la limitación de frecuencia de solicitudes en Swift?
\n\n- \n
- Protección contra la superación de límites de API — muchos servidores (por ejemplo, GitHub, Twitter, Stripe) establecen cuotas estrictas sobre la cantidad de solicitudes por minuto/hora. \n
- Optimización del rendimiento — prevención de una "tormenta" de llamadas durante el desplazamiento rápido o animaciones. \n
- Ahorro de tráfico y batería — especialmente relevante para dispositivos móviles. \n
- Cumplimiento de las políticas de App Store — las solicitudes en segundo plano excesivas pueden provocar el rechazo de la aplicación. \n
Enfoques principales para implementar Rate Limiting en Swift
\n\nConsideremos tres patrones básicos que se pueden implementar sin bibliotecas externas:
\n\n1. Token Bucket (Cubo de fichas)
\nAlgoritmo clásico donde las "fichas" se agregan a una velocidad fija. Cada solicitud consume una ficha. Si no hay fichas, la solicitud es rechazada.
\n\nimport Foundation\n\nfinal class TokenBucket {\n private let capacity: Int\n private var tokens: Int\n private let refillRate: Double // fichas por segundo\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// Ejemplo de uso\nlet limiter = TokenBucket(capacity: 10, refillRate: 2.0) // 10 solicitudes, 2 por segundo\nif limiter.tryConsume() {\n print("✅ Solicitud permitida")\n} else {\n print("⛔️ Límite excedido, espere")\n}\n\n2. Algoritmo de ventana deslizante (Sliding Window)
\nAlmacena las marcas de tiempo de las últimas N solicitudes exitosas. Si la ventana está llena, bloquea nuevas llamadas.
\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 // Eliminar marcas obsoletas\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// Ejemplo: no más de 5 solicitudes en 10 segundos\nlet windowLimiter = SlidingWindowLimiter(maxRequests: 5, windowDuration: 10)\n\n3. Throttling con DispatchQueue
\nUtiliza los mecanismos integrados de GCD para forzar un retraso
También en la biblioteca
Envío de correo electrónico en Go (Golang): bibliotecas y ejemplos de código
Bibliotecas WebSocket TypeScript: ws, Socket.IO, uWebSockets.js
Envío de SMS en C# (.NET): Integración con API de servicios SMS a través de HttpClient
Cliente Redis Swift: RediStack para iOS/macOS