I need to send an array through HTTP to my swift client but I'm not sure how to convert the bytes I've received to a swift array.
I've looked it up on google multiple times with multiple different ways of saying what I'm trying to do but all I'm getting is topics that say "convert byte array to swift string"
AF.request(exampleUrl).response { response in
if let data = response.data, let s = String(data: data, encoding: .utf8) {
debugPrint(s)
let myArray = decodeSomehow(data: data)
debugPrint(myArray[0]) // hooray
}
}
I need to be able to decode arrays sent from my server but my efforts to find the solution to this problem have yielded no results.
btw server is made with firebase functions and is run on Google frontend
and coded with typescript
also to clarify I do not want to take the bytes and put them into an array, I want to decode the bytes into what they originally were on the server aka an array (originally a typescript array but if it is possible to make it a swift array that would be 👌)
The Data class is an advance version of [UInt8]. Normally, working directly with Data class is recommended. If you really want to convert it to [UInt8], simply
let arr = [UInt8](data)
or
let arr = Array(data)
Hope it helps... (Thanks LEO for your best Comment)
let string = "Hello World"
print(Array(string.utf8))
I figured out how to do what I was trying to do...
In the end, I solved my own problem lol
all I needed to do was decode it with swiftyjson
thank you all for your answers
AF.request(exampleUrl).response { response in
if let data = response.data, let s = String(data: data, encoding: .utf8) {
let arr = JSON(data)
debugPrint(arr)
debugPrint(arr[0][0])
debugPrint(s)
}
}
output
Related
Please guys i need to parse a string to look like these in swift
"[{"question":9, "answer":25}", "question\":10, "answer":27}]"
where the index and value are dynamically gotten from a loop. I was able to get to these
["{\"question\":9, \"answer\":25}", "{\"question\":10, \"answer\":27}", "{\"question\":11, \"answer\":29}", "{\"question\":12, \"answer\":33}", "{\"question\":13, \"answer\":37}"]
so i have tried this
for i in 0..<answersForQuestionInPage.count{
let questions = answersForQuestionInPage[i] as Answer
do {
let data = try JSONEncoder().encode(questions)
// 2
let string = String(data: data, encoding: .utf8)!
answers.append(string)
print("This is the main value \(string)")
} catch{
}
}
this still gives me an array with this format
["{\"question\":9, \"answer\":25}", "{\"question\":10,
\"answer\":27}", "{\"question\":11, \"answer\":29}",
"{\"question\":12, \"answer\":33}", "{\"question\":13,
\"answer\":37}"]
with the object
"{\"question\":9, \"answer\":25}"
still wrapped in a string liteal " " what i want is for this return array to be in this format
[{"question":9, "answer":25}, {"question":10,
"answer":27}, {"question":11, "answer":29},
"{"question":12, "answer":33}, {"question":13,
"answer":37}]
I didn't understand the whole thing, but you said you need to parse the String, but I think you meant JSON. So, you can do it like this and get the values. Do let me know if it is what you needed, otherwise please add clarity in your question and I will edit and update my answer accordingly.
struct Quiz: Decodable {
let question, answer: Int
}
private func fetchQuizzes() {
//After getting the data from API, you can do this
guard let quiz = try? JSONDecoder().decode([Quiz].self,from: data) else { print("Unable to parse"); return }
print(quiz)
print(quiz.first?.answer) //First Answer
}
Just like Rob said before, you have a JSON here.
Using Robs code you decode the given JSON and create an array of Quiz objects (Robs struct).
You can now work with that array and transform it to your needs.
I've got the following to listen for new 'message' events with the use of Socket.IO
self.socket.on("message") {data, ack in
print("received data: \(data)")
// do stuff
}
Data I'm getting back in data looks as follows:
[{
conversationid = 1;
message = hello world;
senderid = 1;
}]
It's an array holding a single object but I'm struggling to access the individual elements in there. For example:
let message = ???
Many thanks!
Your data's type is [[String : Any]], if you wanna get the message try this:
Swift 5.x:
if let data = data as? [[String : Any]] {
let message = data[0]["message"] as? String ?? ""
print(message)
}
In this repo you have more info about how to implement socket.io
Played around with it a bit more.
The following works:
let socketResponse = data[0] as? NSDictionary
let message = socketResponse!["message"]
While that solution makes sense to me, it still doesn't make sense why e.g. the solution that #0x0010b suggested doesn't. That one seemed perfectly sound to me as well. Grateful for anyone input that can shed some light on this one ;-)
I want to get a string from a file. I've researched how to do it, and I've found the next code:
import Foundation
// Read data from this file.
let path = "/Users/samallen/file.txt"
do {
// Use contentsOfFile overload.
// ... Specify ASCII encoding.
// ... Ignore errors.
var data = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
// If a value was returned, print it.
print(data)
}
The important part are the lines:
var data = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
I looked in Apple's documentation about this and found init(contentsOfFile:usedEncoding:)
What I don't get is why you can use String(contentsOfFile:usedEncoding:) instead of init(contentsOfFile:usedEncoding:). Why can you replace String for init? I have seen somthing similar with UIImage.
Thanks in advance
I write a little snippet of usual code but found that my code don't return hex data from server with this line of code:
let currentData = try! Data(contentsOf: fullURL!)
print("currentData=", currentData)
And the output:
currentData= 24419 bytes
I tried to use Leo's comment link:
stackoverflow.com/q/39075043/2303865
I got something hex data without spaces, and validator (http://jsonprettyprint.com) can't recognise it and returns null.
Let's try to sort out the different issues here and summarize the
above comments.
The description method
of Data prints only a short summary "NNN bytes", and not a hex dump
as NSData did:
let o = ["foo": "bar"]
let jsonData = try! JSONSerialization.data(withJSONObject: o)
print(jsonData) // 13 bytes
You can get a hex dump by bridging to NSData (source):
print(jsonData as NSData) // <7b22666f 6f223a22 62617222 7d>
or by writing an extension method for Data (How to convert Data to hex string in swift).
But that is actually not the real problem. The JSON validator needs
the JSON as a string, not as a hex dump (source):
print(String(data: jsonData, encoding: .utf8)!) // {"foo":"bar"}
And to de-serialize the JSON data into an object you would need
none of the above and just call
let obj = try JSONSerialization.jsonObject(with: jsonData)
I am trying to create a multiplayer game that will send moves between players using Game Center. I'm still learning a lot about programming, so please excuse me if my question is ill-formed. Also, I am not very familiar with Obj-C, so a Swift answer would be great.
In my toy program to try and teach myself, I am trying to follow the strategy used by Shayne Meyer using the GameKitHelper class here: https://github.com/shaynemeyer/SwiftCircuitRacer/tree/master/SwiftCircuitRacer
Using this approach, Shayne sends messages to other players online using structs sent as NSData. I am able to send integers (e.g., the ILoveYou message) but not messages that carry a string property (e.g., the Thanks message). In this latter case I get "Thread 1: EXC_BAD_ACCESS(code=1, address=0x78674100)" at the line "var messageThanks = UnsafePointer,MesssageThanks>(data.bytes).memory"
Eventually, I would like to send game moves that provide both strings and integers together. How does one send a message struct as NSData when properties also include a string? Secondly, I would be appreciative if someone could help me understand fundamentally what is going on when the data is packaged and how what UnsafePointer is doing as it related to sending data via Game Center.
Thank you.
Cliff
enum MessageType: Int {
case ILoveYou, Thanks
}
struct Message {
let messageType: MessageType
}
struct MessageILoveYou {
let message: Message
let messageSenderNumber: UInt32
}
struct MessageThanks {
let message: Message
let messageSenderName: String
let messageSenderNumber: UInt32
}
func sendILoveYou() {
println("sendILoveYou:")
let nameNumber = UInt32(56)
var message = MessageILoveYou(message: Message(messageType: MessageType.ILoveYou), messageSenderNumber: nameNumber)
let data = NSData(bytes: &message, length: sizeof(MessageILoveYou))
sendData(data)
}
func sendThanks() {
println("sendThanks:")
let nameString = "Don J"
let senderNumberInt = UInt32(88)
var message = MessageThanks(message: Message(messageType: MessageType.Thanks), messageSenderName: nameString, messageSenderNumber: senderNumberInt)
let data = NSData(bytes: &message, length: sizeof(MessageThanks))
sendData(data)
}
func matchReceivedData(match: GKMatch, data: NSData, fromPlayer player: String) {
println("matchReceivedData:")
var message = UnsafePointer<Message>(data.bytes).memory
if message.messageType == MessageType.ILoveYou {
println("messageType == ILoveYou")
let messageILoveYou = UnsafePointer<MessageILoveYou>(data.bytes).memory
iLoveYouThanksDelegate?.iLoveYouReceived(from: messageILoveYou.messageSenderNumber)
} else if message.messageType == MessageType.Thanks {
println("messageType == Thanks")
var messageThanks = UnsafePointer<MessageThanks>(data.bytes).memory
iLoveYouThanksDelegate?.thanksReceived(from: messageThanks.messageSenderName)
}
}
func sendData(data: NSData) {
var sendDataError: NSError?
let gameKitHelper = GameKitHelper.sharedInstance
if let multiplayerMatch = gameKitHelper.multiplayerMatch {
let success = multiplayerMatch.sendDataToAllPlayers(data, withDataMode: .Reliable, error: &sendDataError)
if !success {
if let error = sendDataError {
println("Error:\(error.localizedDescription)")
matchEnded()
}
}
}
}
The problem here is that when you create a String in Swift, it allocates a bit of memory itself, and then uses that memory to store the actual characters of the string. All that the string value really holds is some data representing a pointer to that memory and some other info (like how much memory has been allocated, so that it can be freed properly.
You can see this here:
let str = "This is quite a long string, certainly more than 24 bytes"
sizeofValue(str) // and yet this only returns 24
When you stuff variables into an NSData object, the initializer takes a pointer to the memory of the string variable that is holding those pointers, not the characters itself:
// only storing those 24 bytes, not the actual string
let data = NSData(bytes: &str, length: sizeofValue(str))
Note, the type of the bytes argument is UnsafePointer<Void>. This is an indication that you are heading into tricky territory.
Then, when you unmarshal the data at the other end, all your receiver is going to get is some pointers to random memory (sadly, memory on the other user’s device!)
If you want to put string values into an NSData object, you are going to need to marshal them first into raw data. For example, you could encode them into an array:
let data = Array(str.utf8).withUnsafeBufferPointer { buf in
NSData(bytes: buf.baseAddress, length: buf.count)
}
As it happens, since this is a common thing to want to do, there’s a method to do this directly:
let data = str.dataUsingEncoding(NSUTF8StringEncoding)
Then, to unpack the data, you can use NSString’s constructor from an NSData object:
let newStr = NSString(data: data, encoding: NSUTF8StringEncoding)
edit: if you wanted to encode more than just a string in a single NSData, you could do something along these lines… I should say, I’ve never had to do this myself so I’m in no way familiar with the standard practices for this, there could be much better techniques or helper classes/functions. Hopefully someone with more experience can edit to show how to do this properly :)
var type = MessageType.Thanks
// start the data with the type
let data = NSMutableData(bytes: &type, length: sizeofValue(type))
// then append the string
data.appendData(Array(str.utf8).withUnsafeBufferPointer { buf in
NSMutableData(bytes: buf.baseAddress, length: buf.count)
})
switch UnsafePointer<MessageType>(data.bytes).memory {
case .ILoveYou:
// ...
case .Thanks:
let str = NSString(data: data.subdataWithRange(NSMakeRange(1, data.length-1)), encoding: NSUTF8StringEncoding)
}