在 Swift 中接收 Websocket 数据
Receiving Websocket data in Swift
由于焦点已经改变,我将继续from this question。
我正在尝试通过 websocket 从 vapor 服务器发送字符串数据。客户端是主要问题所在。此代码成功接收到预期为 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 1a35028).(unknown context at 1a350c0).(unknown context at 1a35158).Person(name: "Bobberoo")]
很明显,解码正在进行,但它包含在这些上下文中。这些是什么?我可以看到第一个是 WebSocketController 的实例。我如何访问这些数据。
顺便提一句:管理 JSON 在任何情况下都是一项微不足道的操作。 Python/Flask、节点、Ruby/Rails 等等;我已经使用了所有这些并且实现这种交互是微不足道的。在 Swift,这是一个可怕的、没有记录的噩梦。至少,这是我的经验。为什么?我知道这种语言是类型安全的,但这太荒谬了。
error.localizedDescription
不会给你一个对调试有用的错误信息。另一方面,如果你直接打印 error
:
print(error)
你会得到类似于“预期解码数组但找到字典”的内容,这正是
的情况
{
"name": "Bobberoo"
}
您正在解码 [Person].self
,即 Person
的 数组 ,但您的 JSON 根不是 JSON 大批。上面的 JSON 可以被解码,如果你这样做了:
let people = try decoder.decode(Person.self, from: jsonData)
Clearly, the decoding is happening, but it's wrapped in these contexts. What are they?
这是类型的默认字符串表示形式。您的 Person
结构不符合 CustomStringConvertible
或 CustomDebugStringConvertible
或 TextOutputStreamable
,因此 "an unspecified result is supplied automatically by the Swift standard library"(link 指向 String.init(reflecting:)
,当您 print
Person
的数组时,它可能会在某个地方被调用)并用作字符串表示形式。
据我所知,它的当前实现是结构的完全限定名称 - 从模块开始,然后是顶级 class,然后是每个封闭范围,以结构名称结束,后面是括号中的结构成员。事实证明,封闭范围没有“名称”,因此仅称为 (unknown context at xxxxx)
。这些都是非常多的实现细节,以及您不应该关心的事情。
您应该做的是提供 CustomStringConvertible
:
的实现
struct Person: CustomStringConvertible {
...
var description: String { "name: \(name)" }
}
现在打印 people
得到:
[name: Bobberoo]
I can see that the first is the instance of the WebSocketController
.
没有。 WebSocketController
是 Person
结构的完全限定名称的一部分。您的解码数组中只有一个实例,正如您所期望的那样,它是 Person
的一个实例!
How do I access this data?
要访问其名称:
if let firstPerson = people.first {
let firstPersonsName = firstPerson.name
}
由于焦点已经改变,我将继续from this question。
我正在尝试通过 websocket 从 vapor 服务器发送字符串数据。客户端是主要问题所在。此代码成功接收到预期为 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 1a35028).(unknown context at 1a350c0).(unknown context at 1a35158).Person(name: "Bobberoo")]
很明显,解码正在进行,但它包含在这些上下文中。这些是什么?我可以看到第一个是 WebSocketController 的实例。我如何访问这些数据。
顺便提一句:管理 JSON 在任何情况下都是一项微不足道的操作。 Python/Flask、节点、Ruby/Rails 等等;我已经使用了所有这些并且实现这种交互是微不足道的。在 Swift,这是一个可怕的、没有记录的噩梦。至少,这是我的经验。为什么?我知道这种语言是类型安全的,但这太荒谬了。
error.localizedDescription
不会给你一个对调试有用的错误信息。另一方面,如果你直接打印 error
:
print(error)
你会得到类似于“预期解码数组但找到字典”的内容,这正是
的情况{
"name": "Bobberoo"
}
您正在解码 [Person].self
,即 Person
的 数组 ,但您的 JSON 根不是 JSON 大批。上面的 JSON 可以被解码,如果你这样做了:
let people = try decoder.decode(Person.self, from: jsonData)
Clearly, the decoding is happening, but it's wrapped in these contexts. What are they?
这是类型的默认字符串表示形式。您的 Person
结构不符合 CustomStringConvertible
或 CustomDebugStringConvertible
或 TextOutputStreamable
,因此 "an unspecified result is supplied automatically by the Swift standard library"(link 指向 String.init(reflecting:)
,当您 print
Person
的数组时,它可能会在某个地方被调用)并用作字符串表示形式。
据我所知,它的当前实现是结构的完全限定名称 - 从模块开始,然后是顶级 class,然后是每个封闭范围,以结构名称结束,后面是括号中的结构成员。事实证明,封闭范围没有“名称”,因此仅称为 (unknown context at xxxxx)
。这些都是非常多的实现细节,以及您不应该关心的事情。
您应该做的是提供 CustomStringConvertible
:
struct Person: CustomStringConvertible {
...
var description: String { "name: \(name)" }
}
现在打印 people
得到:
[name: Bobberoo]
I can see that the first is the instance of the
WebSocketController
.
没有。 WebSocketController
是 Person
结构的完全限定名称的一部分。您的解码数组中只有一个实例,正如您所期望的那样,它是 Person
的一个实例!
How do I access this data?
要访问其名称:
if let firstPerson = people.first {
let firstPersonsName = firstPerson.name
}