Rate Limiting em Swift: Guia Completo para Aplicativos iOS e macOS
\n\nRate limiting (limitação de frequência de requisições) é um mecanismo criticamente importante para a operação estável de aplicativos móveis e desktop. No ecossistema Swift (iOS/macOS), esta abordagem permite controlar o número de chamadas de API, operações de entrada/saída ou quaisquer ações repetitivas por unidade de tempo. Sem rate limiting, seu aplicativo corre o risco de ser bloqueado pelo servidor, desperdiçar bateria com tentativas infinitas ou criar carga excessiva na rede.
\n\nPor que a limitação de frequência de requisições é necessária em Swift?
\n\n- \n
- Proteção contra exceder limites de API — muitos servidores (ex.: GitHub, Twitter, Stripe) estabelecem cotas rigorosas para o número de requisições por minuto/hora. \n
- Otimização de desempenho — prevenção de uma "tempestade" de chamadas durante rolagem rápida ou animações. \n
- Economia de tráfego e bateria — especialmente relevante para dispositivos móveis. \n
- Conformidade com as políticas da App Store — requisições em segundo plano excessivas podem levar à rejeição do aplicativo. \n
Abordagens Principais para Implementar Rate Limiting em Swift
\n\nVamos considerar três padrões básicos que podem ser implementados sem bibliotecas de terceiros:
\n\n1. Token Bucket (Balde de Tokens)
\nAlgoritmo clássico onde "tokens" são adicionados a uma taxa fixa. Cada requisição consome um token. Se os tokens acabarem, a requisição é rejeitada.
\n\nimport Foundation\n\nfinal class TokenBucket {\n private let capacity: Int\n private var tokens: Int\n private let refillRate: Double // tokens 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// Exemplo de uso\nlet limiter = TokenBucket(capacity: 10, refillRate: 2.0) // 10 requisições, 2 por segundo\nif limiter.tryConsume() {\n print("✅ Requisição permitida")\n} else {\n print("⛔️ Limite excedido, aguarde")\n}\n\n2. Algoritmo de Janela Deslizante (Sliding Window)
\nArmazena os timestamps das últimas N requisições bem-sucedidas. Se a janela estiver cheia, bloqueia novas chamadas.
\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 // Remove timestamps antigos\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// Exemplo: no máximo 5 requisições em 10 segundos\nlet windowLimiter = SlidingWindowLimiter(maxRequests: 5, windowDuration: 10)\n\n3. Throttling com DispatchQueue
\nUtiliza mecanismos integrados do GCD para atraso forçado
Também na biblioteca
Trabalho com datas em Kotlin: bibliotecas e ferramentas (Kotlinx-datetime, Joda-Time, java.time)
Filas de Tarefas em C# (.NET): System.Threading.Channels e TPL Dataflow
Hilt/Dagger para Kotlin: guia completo com exemplos
Envio de SMS em C++ usando a biblioteca API libcurl