Всем привет.
4 года назад я уже разбирался с вебсокетами в iOS, тогда я решил задачу с помощью одной из библиотек cocoapods, статья есть на Хабре. А сегодня хочу продемонстрировать еще одно решение, нативное без cocoapods.
Я написал свой менеджер для работы с вебсокетами (Менеджер в данном случае синглтон класс который может быть вызван в любом месте приложения, так как это синглтон его экземпляр будет создан только один раз для всего приложения).
Воспользуюсь я для своих целей системным фреймворком CFNetwork.
import Foundation
import CFNetwork
class WSManager {
public static let shared = WSManager() // создаем Синглтон
private init(){}
private var dataArray = [МОДЕЛЬ_МОИХ_ДАННЫХ]()
let webSocketTask = URLSession(configuration: .default).webSocketTask(with: URL(string: "wss://ТУТ_ВАШ_АДРЕС"*))
//функция вызова подключения
public func connectToWebSocket() {
webSocketTask.resume()
self.receiveData() { _ in }
}
//функция подписки на что либо
public func subscribeBtcUsd() {
let message = URLSessionWebSocketTask.Message.string("SUBSCRIBE: НА_ЧТО_ПОДПИСЫВАЕМСЯ")
webSocketTask.send(message) { error in
if let error = error {
print("WebSocket couldn’t send message because: (error)")
}
}
}
//функция отписки от чего либо
public func unSubscribeBtcUsd() {
let message = URLSessionWebSocketTask.Message.string("UNSUBSCRIBE: ОТ_ЧЕГО_ОТПИСЫВАЕМСЯ ")
webSocketTask.send(message) { error in
if let error = error {
print("WebSocket couldn’t send message because: (error)")
}
}
}
//функция получения данных, с эскейпингом чтобы получить данные наружу
func receiveData(completion: @escaping ([МОДЕЛЬ_МОИХ_ДАННЫХ]?) -> Void) {
webSocketTask.receive { result in
switch result {
case .failure(let error):
print("Error in receiving message: (error)")
case .success(let message):
switch message {
case .string(let text):
let data: Data? = text.data(using: .utf8)
let srvData = try? CODABLE_МОДЕЛЬ_ТОГО_ЧТО_ДОЛЖНО_ПРИЙТИ.decode(from: data ?? Data())
for singleData in srvData ?? [] {
self.dataArray.append(МОДЕЛЬ_МОИХ_ДАННЫХ(параметр1: singleData.parametr1, параметр2: singleData.parametr2, параметр3: singleData.parametr3))
}
case .data(let data):
// В вашем варианте данные могут приходить сразу сюда
print("Received data: (data)")
@unknown default:
debugPrint("Unknown message")
}
self.receiveData() {_ in } // рекурсия
}
}
completion(self.dataArray) // отправляем в комплишн то что насобирали в нашу модель
}
}
Вот такой менеджер получился, пример вызова
import UIKit
class MainViewController: UIViewController {
private var dataArray = [МОДЕЛЬ_МОИХ_ДАННЫХ]()
override func viewDidLoad() {
super.viewDidLoad()
WSManager.shared.connectToWebSocket() // подключаемся
WSManager.shared.subscribeBtcUsd() //подписываемся на получение данных
self.getData() //получаем данные
}
private func getData() {
//получаем данные
WSManager.shared.receiveData() { [weak self] (data) in
guard let self = self else { return }
guard let data = data else { return }
self.dataArray = data // кладем данные в переменную и дальше можно делать с ними то что требуется
}
}
}
*по поводу адреса
wss:// это аналог https://
ws:// это аналог http://
Вот такой вариант работы с вебсокетом получился, если есть вопросы, пожелания, поучения как сделать лучше, пишите, буду рад :)
Тестовый пример доступен у меня в гитхабе
Также я использую extension для Decodable который доступен тоже у меня в гитхабе
я про вот эту часть
let srvData = try? CODABLE_МОДЕЛЬ_ТОГО_ЧТО_ДОЛЖНО_ПРИЙТИ.decode(from: data ?? Data())
Автор: Андрей Поснов