Introducción a WebSocket en Swift: de la teoría a la práctica
Las aplicaciones móviles y de escritorio modernas requieren cada vez más una transmisión instantánea de datos. Ya sea un chat, un terminal bursátil, un juego en línea o un sistema de monitoreo, los usuarios esperan que la información se actualice en tiempo real sin necesidad de recargar la pantalla constantemente. Aquí es donde entra en juego el protocolo WebSocket.
A diferencia de la clásica solicitud HTTP, que funciona bajo el principio de "solicitud-respuesta", WebSocket establece una conexión bidireccional permanente entre el cliente y el servidor. Esto significa que el servidor puede enviar datos al cliente en cualquier momento sin una solicitud previa. En el ecosistema de Apple, para trabajar con WebSocket están disponibles tanto soluciones nativas (URLSessionWebSocketTask) como bibliotecas de terceros populares, por ejemplo Starscream.
En este artículo, analizaremos cómo integrar WebSocket en tu aplicación Swift para iOS y macOS, escribiremos ejemplos de código funcionales y revisaremos las mejores prácticas.
1. Implementación nativa de WebSocket mediante URLSession
A partir de iOS 13 y macOS 10.15, Apple proporciona soporte integrado para WebSocket a través de la clase URLSessionWebSocketTask. Esta es la forma más simple y recomendada, que no requiere instalar dependencias de terceros.
Creación y configuración de la conexión
Para empezar, es necesario crear una instancia de URLSession y establecer la configuración. Luego formamos una URL con el protocolo ws:// (o wss:// para conexiones seguras) y creamos una tarea WebSocket.
import Foundation
class WebSocketManager: NSObject { private var webSocketTask: URLSessionWebSocketTask? private let session: URLSession override init() { let config = URLSessionConfiguration.default self.session = URLSession(configuration: config, delegate: nil, delegateQueue: OperationQueue()) super.init() } func connect() { guard let url = URL(string: "wss://echo.websocket.org") else { return } webSocketTask = session.webSocketTask(with: url) webSocketTask?.resume() receiveMessage() } func disconnect() { webSocketTask?.cancel(with: .normalClosure, reason: nil) }}Envío y recepción de mensajes
WebSocket admite el envío tanto de mensajes de texto (URLSessionWebSocketTask.Message.string) como de datos binarios (.data). Para recibir mensajes, es necesario llamar recursivamente al método receive, ya que solo procesa un mensaje a la vez.
extension WebSocketManager { func sendMessage(_ text: String) { let message = URLSessionWebSocketTask.Message.string(text) webSocketTask?.send(message) { error in if let error = error { print("Error de envío: \\(error.localizedDescription)") } } } private func receiveMessage() { webSocketTask?.receive { [weak self] result in switch result { case .success(let message): switch message { case .string(let text): print("Mensaje de texto recibido: \\(text)") case .data(let data): print("Datos binarios recibidos: \\(data.count) bytes") @unknown default: print("Tipo de mensaje desconocido") } // Continuamos escuchando recursivamente self?.receiveMessage() case .failure(let error): print("Error de recepción: \\(error.localizedDescription)") } } }}Observa la llamada recursiva a receiveMessage() dentro del bloque de éxito: esto garantiza que tu aplicación reciba constantemente nuevos datos.