Вариант работы с вебсокетами в iOS на языке Swift – Написал менеджер для работы с websocket

в 14:20, , рубрики: iOS, swift, WebSocket, websockets, xcode, вебсокет, вебсокеты, контроллер, менеджер, мобильная разработка, разработка мобильных приложений, разработка под iOS, сеть

Всем привет.

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())

Автор: Андрей Поснов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js