Swift:如何使用SocketIO emitWithAck方法的响应

时间:2018-06-12 19:23:55

标签: json swift socket.io jsondecoder

我正在使用SocketIO库将我的iOS应用程序连接到我的服务器。 我想向服务器发送一些数据,并在确认中返回一个json字典。我现在有这样的事情:

model = Sequential()
#
# What goes here?
#
model.add(Dense...

MyStruct被定义为继承自Decodable的类,类似于我期望的json的结构。

我收到以下错误:无法将“Any”类型的值转换为预期的参数类型“Data”

我知道如何处理那种类型的铸造吗?或者我需要走另一条路?

(适用于iOS 11.3的Swift 4.1)

干杯!

2 个答案:

答案 0 :(得分:3)

如果还有其他人想知道如何将SocketIO与Decodable结合使用,我根据Dan Karbayev的回答为客户端创建了一个扩展以在回调中接受Decodable。

import Foundation
import SocketIO

extension Decodable {
  init(from any: Any) throws {
    let data = try JSONSerialization.data(withJSONObject: any)
    self = try JSONDecoder().decode(Self.self, from: data)
  }
}

extension SocketIOClient {

  func on<T: Decodable>(_ event: String, callback: @escaping (T)-> Void) {
    self.on(event) { (data, _) in
      guard !data.isEmpty else {
        print("[SocketIO] \(event) data empty")
        return
      }

      guard let decoded = try? T(from: data[0]) else {
        print("[SocketIO] \(event) data \(data) cannot be decoded to \(T.self)")
        return
      }

      callback(decoded)
    }
  }
}

用法:

socket.on("location") { (data: LocationEventData) in
  // ...
}

socket.on("success") { (name: String) in
  // ...
}

LocationEventDataStringDecodable的地方。

答案 1 :(得分:2)

有两件事:

  1. decode(_:from:)接受Data作为第二个参数。为了能够从Any解码,您需要添加扩展名以首先序列化数据,然后将其传递给JSONDecoder,如下所示:

    extension Decodable {
      init(from any: Any) throws {
        let data = try JSONSerialization.data(withJSONObject: any)
        self = try JSONDecoder().decode(Self.self, from: data)
      }
    }
    
  2. AckCallback的参数属于数组类型(即[Any]),因此您应该获取该数组的第一个元素。

  3. 为确保您确实拥有可解码数据(字典或JSON对象),您可以编写如下内容:

    SocketHandler.mySocket.emitWithAck("my_event", [session, someInput]).timingOut(after: 3) { data in
      guard let dict = data.first as? [String: Any] else { return }
      let myData = try? myStruct(from: dict)
      // ...
    }