【问题标题】:Receiving Websocket data in Swift在 Swift 中接收 Websocket 数据
【发布时间】:2021-05-06 08:04:26
【问题描述】:

我在 from this question 上进行此操作,因为焦点已经改变。

我正在尝试通过 websocket 从蒸汽服务器发送字符串数据。客户端是主要问题所在。此代码成功接收字符串,该字符串应为 JSON(但不能绝对保证 -- 超出范围)。

switch message {
case .data(let data):
  print("data: \(data)")

case .string(let str):
  //                    let data = str.message(using: .utf8)

  let jsonData = Data(str.utf8)
  print("string: \(jsonData)")
  do {
    struct Person : Codable {
      var name: String
    }

    let decoder = JSONDecoder()
    let people = try decoder.decode([Person].self, from: jsonData)
    print("result: \(people)")
  } catch {
    print(error.localizedDescription)
  }
}

经过一些非常有用的指导后,发送"{\"name\": \"Bobberoo\"}" 之类的字符串会打印出来

string: 20 bytes
The data couldn’t be read because it isn’t in the correct format.

如果我将它包裹在大括号 "[{\"name\": \"Bobberoo\"}]" 中,会产生更有用但(对我而言)仍然神秘的输出:

result: [wb2_socket_client.WebSocketController.(unknown context at $101a35028).(unknown context at $101a350c0).(unknown context at $101a35158).Person(name: "Bobberoo")]

显然,解码正在发生,但它包含在这些上下文中。这些是什么?我可以看到第一个是 WebSocketController 的实例。如何访问这些数据。

除了非煽动性之外:管理 JSON 在任何情况下都是一项微不足道的操作。 Python/Flask、Node、Ruby/Rails 等等;我已经使用了所有这些并且实现这种交互是微不足道的。在 Swift 中,这是一场可怕的、文献资料不足的噩梦。至少,这是我的经验。为什么?我知道这种语言是类型安全的,但这太荒谬了。

【问题讨论】:

  • 不要 print(error.localizedDescription),打印 error 本身。您将收到更有用的错误消息。

标签: json swift websocket vapor


【解决方案1】:

error.localizedDescription 不会给你一个对调试有用的错误消息。另一方面,如果你直接打印error

print(error)

您会得到类似于“预期解码数组但找到字典”的内容,这正是发生在

的情况
{
    "name": "Bobberoo"
}

您正在解码[Person].self,即Person数组,但您的 JSON 根不是 JSON 数组。如果你这样做了,上面的 JSON 可以被解码:

let people = try decoder.decode(Person.self, from: jsonData)

显然,解码正在发生,但它包含在这些上下文中。它们是什么?

这是一个类型的默认字符串表示。您的Person 结构不符合CustomStringConvertibleCustomDebugStringConvertibleTextOutputStreamable,所以"an unspecified result is supplied automatically by the Swift standard library"(链接指向String.init(reflecting:),当您print Person) 并用作字符串表示形式。

据我所知,它当前的实现是结构的完全限定名称 - 从模块开始,然后是顶级类,然后是每个封闭范围,以结构名称结尾,然后是结构的成员括号。事实证明,封闭范围没有“名称”,因此仅称为(unknown context at xxxxx)。这都是非常多的实现细节,以及你不应该关心的事情。

你应该做的是提供CustomStringConvertible的实现:

struct Person: CustomStringConvertible {
    ...

    var description: String { "name: \(name)" }
}

现在打印people 给出:

[name: Bobberoo]

我可以看到第一个是WebSocketController的实例。

没有。 WebSocketControllerPerson 结构的完全限定名称的一部分。您的解码数组中只有一个实例,它是Person 的实例,正如您所料!

我如何访问这些数据?

要访问它的名字:

if let firstPerson = people.first {
    let firstPersonsName = firstPerson.name
}

【讨论】:

  • 这行得通,很好。你的回答很明确,也很中肯。作为一个开始学习这一点的人,我真的很感激时间和精力。很多 Swift 似乎是“可反向发现的”:在帮助上下文中,我了解了 CustomStringConvertible,现在我可以研究它了。但我确信这不是我一直在研究的信息的一部分,这令人沮丧。我的代码中的很多内容确实来自其他人的教程、课程等,但是这个作为障碍的细节让我感到沮丧。所以我更加感激它。
猜你喜欢
  • 1970-01-01
  • 2012-08-24
  • 2014-12-09
  • 1970-01-01
  • 2015-04-01
  • 2020-09-18
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多