Introducción: Por qué WebSocket es importante para el desarrollador de Swift
Las aplicaciones móviles y de escritorio modernas requieren cada vez más un intercambio instantáneo de datos. Ya sea un chat, un terminal bursátil, un juego en línea o un sistema de notificaciones push, los usuarios esperan una reacción en tiempo real. El protocolo WebSocket se ha convertido en el estándar para estas tareas, y en el ecosistema Swift (iOS/macOS) su soporte está implementado de forma nativa a través de URLSessionWebSocketTask.
En este artículo, analizaremos el ciclo completo de trabajo con WebSocket en Swift: desde la configuración de la conexión hasta la creación de una aplicación completa en tiempo real. Aprenderá cómo evitar errores típicos, organizar la reconexión e integrar WebSocket en la arquitectura MVVM.
Fundamentos de WebSocket en Swift: URLSessionWebSocketTask
A partir de iOS 13 y macOS 10.15, Apple proporciona la clase integrada URLSessionWebSocketTask dentro de Foundation. Esto evita la necesidad de conectar bibliotecas de terceros (por ejemplo, Starscream) para escenarios básicos.
Creación de una conexión WebSocket
Para establecer la conexión, es necesario crear una sesión URLSession y configurarla:
import Foundation
class WebSocketManager { private var webSocketTask: URLSessionWebSocketTask? private let session: URLSession init() { let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 30 config.waitsForConnectivity = true session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) } func connect() { guard let url = URL(string: "wss://echo.websocket.org") else { return } webSocketTask = session.webSocketTask(with: url) webSocketTask?.resume() receiveMessage() }}Tenga en cuenta waitsForConnectivity — esto permite restaurar automáticamente la conexión cuando aparece la red.
Envío y recepción de mensajes
WebSocket admite dos tipos de mensajes: texto (String) y binarios (Data). Veamos un ejemplo de envío:
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)") } }}
func sendData(_ data: Data) { let message = URLSessionWebSocketTask.Message.data(data) webSocketTask?.send(message) { error in // manejo del error }}Para recibir mensajes se utiliza una llamada recursiva a receive:
private func receiveMessage() { webSocketTask?.receive { [weak self] result in switch result { case .success(let message): switch message { case .string(let text): print("Texto recibido: \\(text)") case .data(let data): print("Datos recibidos: \\(data.count) bytes") @unknown default: break } // Seguimos escuchando self?.receiveMessage() case .failure(let error): print("Error de recepción: \\(error)") } }}Importante: la llamada a receive solo maneja un mensaje. Para recibir datos de forma continua, debe llamarse nuevamente dentro del bloque de éxito.
Arquitectura de una aplicación en tiempo real en Swift
Para el uso industrial de WebSocket, es necesario diseñar la arquitectura. Se recomienda usar una capa de servicio con un protocolo y un delegado para separar la lógica de red de la interfaz de usuario.
Protocolo del servicio WebSocket
protocol WebSocketServiceProtocol: AnyObject { var isConnected: Bool { get } func connect() func disconnect() f