Не нашел ни одного актуального гайда по работе с websocket в Xcode, вот мой опыт, надеюсь какому-то новичку поможет, и он не потратит столько времени в поисках как я.

Для подключения по websocket мы будем использовать SocketIOClientSwift

Скачать можно тут.

Установка там тоже в принципе описывается, но для тех кто совсем в танке расскажу, что есть простой способ, просто добавьте файлы из папки source в свой проект.

В нашем примере мы будем получать тикеты из системы технической поддержки которая работает на node.js

Создаем массив наших тикетов (пока что пустой):

 var arrayOfTickets:[String] = []

Можно сделать получение данных по кнопке или при загрузке, в нашем примере при загрузке.

    override func viewDidLoad() {
        super.viewDidLoad()

            let hostUrl = NSURL(string:"http://IP_или_домен:ПОРТ")! //тут указываем адрес подключения
            let tokenSDK = "ТОКЕН ЕСЛИ ЕСТЬ" //тут токен если есть
            let socket = SocketIOClient(socketURL: hostUrl, options: ["log": false,
            "reconnects": true,
            "reconnectAttempts": 1,
            "reconnectWait": 1,
            "connectParams": ["token":tokenSDK]]) // тут задаем параметры передачи данных
        
            socket.on("connect") {data,ack in
            
            let hejka = [""] // тут параметр (если есть)
            let paginav = [""] // тут параметр 2 (если есть)
            
            socket.emitWithAck("ВАШЕ_СОБЫТИЕ", "", hejka, paginav)(timeoutAfter: 0) // указываем событие которое генерируем
                {data in
                
                let dataTickets = data[1]["result"] as! NSArray // парсим json который пришел
                let howMuchTickets = dataTickets.valueForKey("name")
                
                
                for (var i=0; i < howMuchTickets.count; i++){
                    let ticketName = dataTickets[i].valueForKey("name") as? String
                    self.arrayOfTickets.append(ticketName!) // заполняем массив тикетов
                                   }

             }
        }
        
        socket.connect()

Считаем сколько нам нужно сгенерировать ячеек в таблице:

 override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return arrayOfTickets.count
    }

Выводим данные (у нас в примере кастомные ячейки, как их сделать не суть моего поста, но если есть вопросы — пишите):

   override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // dequeue the cell from our storyboard
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
        
        // if the cell has a text label, set it to the model that is corresponding to the row in array
        cell.ticketName?.text = arrayOfTickets[indexPath.row]
        
        // return cell so that Table View knows what to draw in each row
        return cell
    }

Теперь для самых внимательных, как мы знаем запрос идет асинхронный, и при выполнении это кода, у нас ничего не появится.

Для того чтобы появилось нам нужно вызвать функцию tableview, и сказать ей чтобы перезагрузила данные, то есть добавим одну строку.

 override func viewDidLoad() {
        super.viewDidLoad()

            let hostUrl = NSURL(string:"http://IP_или_домен:ПОРТ")! //тут указываем адрес подключения
            let tokenSDK = "ТОКЕН ЕСЛИ ЕСТЬ" //тут токен если есть
            let socket = SocketIOClient(socketURL: hostUrl, options: ["log": false,
            "reconnects": true,
            "reconnectAttempts": 1,
            "reconnectWait": 1,
            "connectParams": ["token":tokenSDK]]) // тут задаем параметры передачи данных
        
            socket.on("connect") {data,ack in
            
            let hejka = [""] // тут параметр (если есть)
            let paginav = [""] // тут параметр 2 (если есть)
            
            socket.emitWithAck("ВАШЕ_СОБЫТИЕ", "", hejka, paginav)(timeoutAfter: 0) // указываем событие которое генерируем
                {data in
                
                let dataTickets = data[1]["result"] as! NSArray
                let howMuchTickets = dataTickets.valueForKey("name")
                
                
                for (var i=0; i < howMuchTickets.count; i++){
                    let ticketName = dataTickets[i].valueForKey("name") as? String
                    self.arrayOfTickets.append(ticketName!) // // заполняем массив тикетов
                   self.tableView.reloadData()  // ВОТ ЭТА СТРОКА
                 }

             }
        }
        
        socket.connect()

Надеюсь гайд будет полезен, если есть вопросы или вы знаете как сделать лучше/быстрее/красивее пишите.

Комментарии (26)


  1. farcaller
    20.02.2016 17:10
    +3

    let dataTickets = data[1]["result"] as! NSArray

    отличный рецепт получить креш, когда ваше http:// соединение перехватит редиректор провайдера.


    1. mlnewton
      21.02.2016 00:10

      не очень понял, как лучше делать?


      1. farcaller
        21.02.2016 00:21

        as! обязан убить приложение при несоответствии типа. Тип надо проверять, впрочем как и наличие элемента 1 и словаря с ключем "result" внутри. Всегда проверяйте все что вы получаете из внешних источников.


  1. DevAndrew
    20.02.2016 23:11

    В сторону библиотеки Starscream смотрели?


    1. mlnewton
      21.02.2016 00:11

      честно говоря, что нагуглил тем и воспользовался, а starscream чем лучше, какие плюсы? а так интересно, посмотрю


      1. DevAndrew
        21.02.2016 15:28

        Я пока что не применял. Думал вы делали какой то сравнительный анализ, вот и решил уточнить.


  1. PapaBubaDiop
    20.02.2016 23:48
    +2

    Зачем

    self.tableView.reloadData()

    внутри цикла?


    1. mlnewton
      21.02.2016 00:12
      -1

      так работает… что плохого? как лучше было сделать?


      1. storoj
        21.02.2016 00:30
        +1

        1. mlnewton
          21.02.2016 12:01

          спасибо, посмотрю.


      1. PapaBubaDiop
        21.02.2016 01:02
        +1

        За скобки вынести? Чтоб один раз отработало, а не 500. И можно с анимацией появления, красиво так, вжи-и-и-к.


        1. mlnewton
          21.02.2016 12:02

          А как можете написать пример или посоветовать где посмотреть?


      1. vikarti
        21.02.2016 07:29

        что то вроде
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow: XXXX inSection:0];
        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        тут не лучще?


        1. mlnewton
          21.02.2016 12:04

          Может и лучше, а как будет это на Swift?


  1. storoj
    21.02.2016 00:34

    и кто такой Minsu Kim?


    1. mlnewton
      21.02.2016 12:05

      советуете его почитать? Кто это?


  1. DnV
    21.02.2016 01:22

    Как работать с вебсокетами? Юзайте ту библиотечку и не забывайте перезагружать табличку!


    1. mlnewton
      21.02.2016 12:06

      можно и так сказать ) Как новичок очень долго искал эту информацию, поэтому пусть кому-нибудь поможет такому же новичку как я.


  1. vikarti
    21.02.2016 07:08

    вообще есть например простой пример работы с вебсокетами https://habrahabr.ru/post/214579/ (только там табличку перезагружать не предлагают)


    1. mlnewton
      21.02.2016 12:08

      Там к сожалению на objective-c.


  1. landan
    25.02.2016 19:34

    Зачем это на хабре? Во первых, на гитхабе того же Socket.IO-Client-Swift есть примеры, во вторых, вы подаете плохой пример для начинающих.


    1. mlnewton
      25.02.2016 20:21

      Не нашел ни одного гайда под swift для начинающих как я, чем плох пример?


      1. landan
        25.02.2016 20:58

        Пример использования socket.io-client https://github.com/socketio/socket.io-client-swift
        Примеры с tableView на свифте гуглятся за 5 секунд.
        Пример плох тем, что вы просто смешали все в кучу, сокеты, таблицы, парсинг json и тд, так не делается. Если детальнее, то начнем с того, что SocketIOClient имеет специальный enum для опций. Дальше насчет парсинга, напрямую с dictionary и json никто не работает, создайте модели и используйте десериализатор, если нет кастомных вложеных обьектов, то можете использовать стандартный, или что-то более удобнее типа Gloss или EVEReflector.
        Ну и self.tableView.reloadData() в цикле — это что-то =)


        1. mlnewton
          25.02.2016 21:01

          Вы молодец, что такой умный, но мне например не понятны примеры с гитхаба. И многим судя по вопросам в личке требуется помощь чтобы разобраться. Более того 70% того что Вы написали мне не понятно. Это статья для новичков таких же как я. Просто статья не для Вас, Вы более продвинутый.


          1. landan
            25.02.2016 21:08

            Да вы поймите, ничего личного, все новичками были, но просто статья как мне кажется не уровень хабра, ну гуглится все элемтарно же.


            1. mlnewton
              25.02.2016 21:11

              я не смог нагуглить, и те 5 человек что мне написали тоже, я рад что им помог и тем 52 людям которые добавили в избранное статью, если Вам легче нагуглить, это Ваш выбор.