我从这个问题开始讲,因为焦点已经改变了。
我正试图通过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等;我已经使用了所有这些,实现这种交互是微不足道的。在斯威夫特身上,这是一场可怕的、记录不足的噩梦。至少,这是我的经验。为什么?我知道这种语言是打字安全的,但这太荒谬了。
error.localizedDescription
不会向您提供对调试有用的错误消息。另一方面,如果直接打印error
:
print(error)
你会得到一些类似于";期望解码数组,但却找到字典";,这正是的情况
{
"name": "Bobberoo"
}
您正在解码[Person].self
,即Person
的数组,但您的JSON根不是JSON数组。如果你这样做了,上面的JSON可以被解码:
let people = try decoder.decode(Person.self, from: jsonData)
很明显,解码正在进行,但它被包裹在这些上下文中。它们是什么?
这是类型的默认字符串表示形式。您的Person
结构不符合CustomStringConvertible
、CustomDebugStringConvertible
或TextOutputStreamable
,因此";Swift标准库"自动提供未指定的结果;(链接指向String.init(reflecting:)
,当您print
Person
的数组时,它可能会在某个地方被调用),并用作字符串表示。
从我所看到的,它的当前实现是结构的完全限定名称——从模块开始,然后是顶级类,然后是每个封闭范围,以结构名称结束,然后是括号中的结构成员。事实证明,封闭的作用域没有";名称";,因此被称为CCD_ 14。这些都是非常多的实现细节,以及您不应该关心的事情。
您应该做的是提供CustomStringConvertible
:的实现
struct Person: CustomStringConvertible {
...
var description: String { "name: (name)" }
}
现在打印people
给出:
[name: Bobberoo]
我可以看到第一个是
WebSocketController
的实例。
否。WebSocketController
是Person
结构的完全限定名称的一部分。正如您所期望的,在您解码的数组中只有一个实例,它就是Person
的实例!
如何访问此数据?
访问其名称:
if let firstPerson = people.first {
let firstPersonsName = firstPerson.name
}