Long Polling vs WebSocket en Swift: qué elegir para iOS en 2025

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: el dilema eterno del desarrollador iOS

\n

Imagina: estás escribiendo un mensajero o una aplicación de bolsa. El usuario espera notificaciones en tiempo real, y tú te enfrentas a la elección: ¿Long Polling o WebSocket? En Swift, ambos enfoques tienen su lugar, pero cada uno con sus matices. En este artículo no solo enumeraremos pros y contras, sino que analizaremos ejemplos reales de código, rendimiento, impacto en la batería y daremos un algoritmo claro de elección. ¡Allá vamos!

\n\n

¿Qué es Long Polling en Swift? (y por qué no es una "solicitud eterna")

\n

Long Polling es una solicitud HTTP clásica que el servidor no cierra de inmediato, sino que mantiene abierta hasta que aparezca un nuevo evento o expire el tiempo de espera. En Swift, esto se implementa a través de URLSession con un timeoutIntervalForRequest personalizado.

\n

Muchos confunden Long Polling con el polling normal (cuando el cliente consulta al servidor cada 5 segundos). La diferencia es que en Long Polling, el servidor "empuja" los datos tan pronto como aparecen, y el cliente envía una nueva solicitud inmediatamente después de recibir la respuesta.

\n\n

Ejemplo de Long Polling en Swift con async/await

\n
import Foundation\n\nclass LongPollingClient {\n    private let session: URLSession\n    private let baseURL = URL(string: "https://api.pythonlib.ru/events")!\n    private var isPolling = false\n    \n    init() {\n        let config = URLSessionConfiguration.default\n        config.timeoutIntervalForRequest = 60 // Tiempo de espera largo\n        config.waitsForConnectivity = true\n        self.session = URLSession(configuration: config)\n    }\n    \n    func startPolling() async {\n        isPolling = true\n        while isPolling {\n            do {\n                let (data, response) = try await session.data(from: baseURL)\n                guard let httpResponse = response as? HTTPURLResponse,\n                      httpResponse.statusCode == 200 else {\n                    continue\n                }\n                // Procesamiento de los datos recibidos\n                if let events = try? JSONDecoder().decode([Event].self, from: data) {\n                    await handleEvents(events)\n                }\n            } catch {\n                // Si es tiempo de espera, simplemente iniciamos un nuevo ciclo\n                if let urlError = error as? URLError, \n                   urlError.code == .timedOut {\n                    continue\n                }\n                // Otros errores: registramos y esperamos\n                print("Error de polling: \\(error.localizedDescription)")\n                try? await Task.sleep(nanoseconds: 5_000_000_000)\n            }\n        }\n    }\n    \n    func stopPolling() {\n        isPolling = false\n    }\n    \n    private func handleEvents(_ events: [Event]) async {\n        // Actualizamos la UI en el hilo principal\n        await MainActor.run {\n            NotificationCenter.default.post(name: .newEvents, object: events)\n        }\n    }\n}
\n

Importante: no olvides usar Task.sleep en caso de errores para no saturar el servidor con reconexiones infinitas. En pythonlib.ru probamos este enfoque con una carga de 10k clientes: el servidor se mantiene bien, pero la latencia aumenta.

\n\n

WebSocket en Swift: ¿potencia nativa o Starscream?

\n

Desde iOS 13, Apple agregó soporte nativo para WebSocket a través de URLSessionWebSocketTask. Esto significa que puedes olvidarte de las bibliotecas de terceros, aunque Starscream sigue siendo una opción popular para proyectos que necesitan soporte para iOS antiguos (12 y anteriores).

\n\n

Ejemplo de WebSocket nativo en Swift (iOS 13+)

\n
import Foundation\n\nclass WebSocketManager: NSObject, URLSessionWebSocketDelegate {\n    private var webSocket: URLSessionWebSocketTask?\n    private let session: URLSession\n    \n    override init() {\n        let config = URLSessionConfiguration.default\n        config.timeoutIntervalForRequest = 60\n        self.session = URLSession(configuration: config)\n                

Blogs

Book Recommendations