Kim Johnsson
Kim Johnsson

Reputation: 33

Converting socket.io data to JSON in Swift

I'm writing a socket.io client and I'm having trouble getting the emitted data into any usable format.

My handler is:

socket.on("foriEvent") { data, ack in
    print(data)
}

which prints:

[  
   {  
      "foriEvent":{  
         "eventType":"location",
         "state":"moving",
         "latitude":"60.4413407",
         "longitude":"22.2476208",
         "accuracy":"20",
         "ts":1510653600189
      }
   }
]

I have a Struct that "looks" like that data, and I would like to use something like this where the from object is of type Data.

let decoder = JSONDecoder()
let foriEvent = try decoder.decode(ForiEvent.self, from: data)

Currently I'm using the following to get a Data object, but when I send it to decoder.decode, I get the following error message:

return try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted)
error trying to convert data to JSON typeMismatch(Swift.Dictionary<Swift.String, Any>, 
Swift.DecodingError.Context(codingPath: [], debugDescription:
"Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

Could it be my struct? What should it look like? The Struct looks like this right now:

struct ForiEvent : Codable {
    var eventType: String?
    var state : String?
    var latitude: String?
    var longitude : String?
    var accuracy : String?
    var timeStamp : CLong?
}

struct ForiData : Codable {
    var foriEvent : ForiEvent?
}

Upvotes: 2

Views: 3288

Answers (3)

Bamz3r
Bamz3r

Reputation: 187

Using SwiftyJSON is easiest way to handle json

Use this example

socket.on("foriEvent") { data, ack in
   // because 'data' is type of [Any] so we can use 'JSON.init(AnyObject)'
   let json:JSON = JSON(data[0])//JSON.init(parseJSON: cur)
    // variable json is ready for use as this json["foriEvent"]
}

Upvotes: 2

Nevin Jethmalani
Nevin Jethmalani

Reputation: 2826

I use swiftyjson for this. It does a great job.

You haven't defined what type the data is but if it is a string which it looks like it is from the print command that you have then you can do this.

    guard let dataFromString = data[0].data(using: String.Encoding.utf8, allowLossyConversion: false) else {return}
    var swiftyJson:JSON!
    do {
        swiftyJson = try JSON(data: dataFromString)
    } catch {
        print("Error JSON: \(error)")
    }

This will give you the data in JSON format which you can very easily parse using swiftyjson into the custom type you have outlined above. The reason that Codable might not be working is because your JSON is returned as an array of JSON.

Try this

let tempVar = swiftyJson["foriEvent"]["eventType"].string
print("test \(tempVar)") 

Upvotes: 1

Pramod Kumar
Pramod Kumar

Reputation: 2652

I think there is no need to implement any third party (BTW I'm not againsed to SwiftyJson or any other). You can do it as:

//Here is the new struct for your ForiEvent
struct ForiEvent {
var eventType: String?
var state : String?
var latitude: String?
var longitude : String?
var accuracy : String?
var timeStamp : CLong?

init(dict: [String:Any]) {
    if let obj = dict["eventType"] {
        eventType = "\(obj)"
    }

    if let obj = dict["state"] {
        state = "\(obj)"
    }

    if let obj = dict["latitude"] {
        latitude = "\(obj)"
    }

    if let obj = dict["longitude"] {
        longitude = "\(obj)"
    }

    if let obj = dict["accuracy"] {
        accuracy = "\(obj)"
    }

    if let obj = dict["timeStamp"] as? CLong {
        timeStamp = obj
    }
}
}

//You data as [[String:Any]] returend from on complitionhandler
let dictArray:[[String:Any]] = [[
"foriEvent":[
    "eventType" : "location",
    "state":"moving",
    "latitude":"60.4413407",
    "longitude":"22.2476208",
    "accuracy":"20",
    "ts":1510653600189
]
]
]

print(dictArray)


// How to Use it:
var foriEventArray = [ForiEvent]()
for eventData in dictArray {
if let eventDict = eventData["foriEvent"] as? [String:Any] {
    foriEventArray.append(ForiEvent(dict: eventDict))
}
}
print(foriEventArray)

Upvotes: 1

Related Questions