问题
I'm carrying this on from this question, since the focus has changed.
I am trying to send string data from a vapor server over a websocket. The client side is where the main question is. This code successfully receives the string, which is expected to be JSON (but not absolutely guaranteed -- out of scope).
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)
}
}
After some very helpful guidance, sending a string such as "{\"name\": \"Bobberoo\"}"
will print out
string: 20 bytes
The data couldn’t be read because it isn’t in the correct format.
If I wrap it in braces "[{\"name\": \"Bobberoo\"}]"
produces the more helpful but still mystifing (to me) output:
result: [wb2_socket_client.WebSocketController.(unknown context at $101a35028).(unknown context at $101a350c0).(unknown context at $101a35158).Person(name: "Bobberoo")]
Clearly, the decoding is happening, but it's wrapped in these contexts. What are they? I can see that the first is the instance of the WebSocketController. How do I access this data.
And as a non-inflammatory aside: managing JSON is a trivial operation in any number of contexts. Python/Flask, Node, Ruby/Rails and on and on; I've used all these and implementing this kind of interaction is trivial. In Swift, it's a horrible, underdocumented nightmare. At least, that's my experience. Why? I know the language is type safe, but this is ridiculous.
回答1:
error.localizedDescription
won't give you an error message that is useful message for debugging. On the other hand, if you print error
directly:
print(error)
You'd get something along the lines of "expected to decode array but found dictionary instead", which is exactly what is happening in the case of
{
"name": "Bobberoo"
}
You are decoding a [Person].self
, i.e. an array of Person
, but your JSON root is not a JSON array. The above JSON can be decoded if you did:
let people = try decoder.decode(Person.self, from: jsonData)
Clearly, the decoding is happening, but it's wrapped in these contexts. What are they?
This is the default string representation of a type. Your Person
struct does not conform to CustomStringConvertible
or CustomDebugStringConvertible
or TextOutputStreamable
, so "an unspecified result is supplied automatically by the Swift standard library" (the link points to String.init(reflecting:)
, which presumably gets called somewhere along the way when you print
the array of Person
) and used as the string representation.
From what I can see, its current implementation is the fully qualified name of the struct - starting with the module, then the top-level class, then each enclosing scope, ending with the struct name, followed by the struct's members in brackets. It turns out that the enclosing scopes has no "names", and so are just called (unknown context at xxxxx)
. This is all very much implementation details, and things that you shouldn't care about.
What you should do, is provide an implementation of CustomStringConvertible
:
struct Person: CustomStringConvertible {
...
var description: String { "name: \(name)" }
}
Now printing people
gives:
[name: Bobberoo]
I can see that the first is the instance of the
WebSocketController
.
No. The WebSocketController
is part of the fully qualified name of your Person
struct. There is exactly one instance in your decoded array, and it's an instance of Person
, as you would expect!
How do I access this data?
To access its name:
if let firstPerson = people.first {
let firstPersonsName = firstPerson.name
}
来源:https://stackoverflow.com/questions/66004678/receiving-websocket-data-in-swift