Remove unwanted data from JSON using swift - json

I am getting response
{"msg":"Success: Mobile Number is Valid","status":0}396b6c706a54383638343131
How can I get valid JSON from my API response using swift I am getting JSON error.
Code:
NSLog("Login response: " + response, "response")
let jsonTag = JSON(response.dropLast(24).data(using: .utf8)!)
let loginModelRootClass = LoginModelRootClass(fromJson: jsonTag )
if (loginModelRootClass.status == 0)
{
/* successfully login */
NSLog("Login response: " + loginModelRootClass.msg, "response")
}
else
{
/* failure login */
NSLog("Login response: " + loginModelRootClass.msg, "response")
New to swift please help.

I agree with the comments that the best option is to get the backend to send valid json. However if that is not possible, you could use the function below to remove the invalid trailing data and then decode with Codable
func clean(json: String) -> String? {
guard let closing = json.lastIndex(of: "}") else {return nil}
var string = json
let range = string.index(after: closing)..<string.endIndex
string.removeSubrange(range)
return string
}

Related

Converting a String to json in Swift. for sending in a websocket

I have a JS to send Json via websocket. as follows:
function senddata()
{
var obj = {};
var arrayOfRequests = [];
arrayOfRequests.push({
"id":22,
"repeat":false,
})
obj.DataReq = arrayOfRequests;
var stringToSend = JSON.stringify(obj);
websocketConnection.send( stringToSend );
}
This code works as expected, and the server sends back the requested info.
I am trying to do the same thing in swift.
func send(text: String) {
let message = text
guard let json = try? JSONEncoder().encode(message),
let jsonString = String(data: json, encoding: .utf8)
else {
return
}
webSocketTask?.send(.string(jsonString)){ error in
if let error = error {
print("Error sending message", error)
}
}
}
send(text: "{“DataReq”:[{“id”:22,“repeat”:false}]}")
With this the server does not send any response.
If Connect both of these examples to a websocket echo server
the JS code sends {"DataReq":[{"id":22,"repeat":false}]}
while the Swift codes send "{"DataReq":[{"id":9,"repeat":false}]}".
any help is appreciated.
Encoding a JSON string to JSON is pointless. Remove the encoding part
func send(text: String) {
webSocketTask?.send(.string(text)){ error in
if let error = error {
print("Error sending message", error)
}
}
}
And in the send line the double quotes are invalid. Use this syntax
send(text: #"{"DataReq":[{"id":22,"repeat":false}]}"#)

SwiftyJSON - Unable to get transactionId from JSON String

I am using CocoaAsyncSocket to retrieve a message from a servers API that's using JSON. I am able to get the data and convert it to a printable string, what I am unable to do is retrieve a value (transactionId) from my attempts to parse the JSON string I already have, using SwiftyJSON. I know there are other posts that are similar to this one but none have solved my problem.
In ViewController:
func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
guard let msg = String(data: data, encoding: .utf8) else { return }
var response = " "
if msg.contains("Reset") {
transactionID = ParseJSON().parse(message: msg)
response = String(format: "{\"Response\":{\"transactionId\":\"%#%\",\"content\":{\"Reset\":{}}}}", transactionID)
socket.write((response.data(using: .utf8))!, withTimeout: -1, tag: 0)
}
socket?.readData(withTimeout: -1, tag: 0)
}
ParseJSON class:
func parse (message: String) -> String {
var parsedMessage = " "
let json = JSON(parseJSON: message)
let transactionId = json["Request"]["transactionId"].stringValue
parsedMessage = transactionId
print(parsedMessage)
return parsedMessage
}
The result that is displayed is an empty transactionId value. Nothing prints or anything.
If you spot any errors in my code or have a better approach then please let me know!
Edit:
Here is the string I am attempting to parse:
{"Request": {"content": {"Reset": {}}, "transactionId": "f7c4d630-552b-46d9-a37d-44450537b48d"}}
Here is my output:
{\"Response\":{\"transactionId\":\"\",\"content\":{\"Reset\":{}}}}
The problem is not the code. Consider:
func parse(message: String) -> String {
let json = JSON(parseJSON: message)
return json["Request"]["transactionId"].stringValue
}
let input = """
{"Request": {"content": {"Reset": {}}, "transactionId": "f7c4d630-552b-46d9-a37d-44450537b48d"}}
"""
let transactionID = parse(message: input)
print("transactionId:", transactionID)
let response = String(format: "{\"Response\":{\"transactionId\":\"%#\",\"content\":{\"Reset\":{}}}}", transactionID)
print("response:", response)
The result of the above, as you’d expect, is:
transactionId: f7c4d630-552b-46d9-a37d-44450537b48d
response: {"Response":{"transactionId":"f7c4d630-552b-46d9-a37d-44450537b48d","content":{"Reset":{}}}}
So I suspect that the input message is not quite what you expected. So I might suggest adding some error handling so you can diagnose precisely where it is going wrong:
func parse(message: String) -> String {
let json = JSON(parseJSON: message)
if let error = json.error {
fatalError("JSON parsing error: \(error)")
}
let request = json["Request"]
if let error = request.error {
fatalError("request error: \(error)")
}
let transactionId = request["transactionId"]
if let error = transactionId.error {
fatalError("transactionId error: \(error)")
}
return transactionId.stringValue
}
Now, in practice, you probably wouldn’t use fatalError, but rather would do some graceful error handling (e.g. change parse such that it throws, then throw the errors encountered, if any, and then catch the error where you call parse and handle any runtime issues gracefully). But during this diagnostic process, fatalError is useful because it will stop your debugger at the offending line, simplifying your diagnostic process.
Bottom line, the request must not be quite in the form you expect. Note, it’s going to be very sensitive to capitalization, malformed JSON, etc. So, by looking at the errors provided by SwiftyJSON, you should be able to narrow down the issue quite quickly.
Below, you tell us that the Data is:
<7b225265 71756573 74223a20 7b22636f 6e74656e 74223a20 7b225265 73657422
3a207b7d 7d2c2022 7472616e 73616374 696f6e49 64223a20 22643937 36303036
622d3130 38302d34 3864652d 39323232 2d623139 63363663 35303164 31227d7d
00>
The problem is that last byte, 0x00. If you remove that, it works.
FWIW, when I convert that hex string back to a Data and run it through JSONSerialization, it confirms the diagnosis:
Error Domain=NSCocoaErrorDomain
Code=3840 "Garbage at end."
UserInfo={NSDebugDescription=Garbage at end.}
You need to figure out why that 0x00 was included in the end of your payload and remove it.

swift: JSON not working correctlly after changing device language

I made JSON request to get goole YouTube search suggestions, if I pass an Arabic lettrs as a search keyword it works fine if the device language is English, but if I change it to Arabic I got this message:
JSON could not be serialized because of error:
The data couldn’t be read because it isn’t in the correct format.
The code:
//Prepare Keyword string
searchKeyword = (searchKeyword as NSString).replacingOccurrences(of: " ", with: "+")
//Prepare url string
var str: String = "http://suggestqueries.google.com/complete/search?ds=yt&client=firefox&hjson=t&q='\(searchKeyword)'"
str = str.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!
//Getting the data
Alamofire.request(str).responseJSON { (response) in
//If error
if let error = response.error {
print(error.localizedDescription)
}
//If successed
if let jsonArray = response.result.value as? NSArray {
//Use the data
}
}
Remark:
when the device is in English interface I got Content-Type = charset=ISO-8859-1 in JSON response description
but when the device is in Arabic interface Content-Type = charset=windows-1256
I added this line and the problem is resolved!!
UserDefaults.standard.set(["ar", "en"], forKey: "AppleLanguages")

How to decode a base 64 string found in a JSON string to generate a UIImage?

I have pasted my code below. Essentially, I have been given an SDK, which has a JSON string that I then have to parse in order to get to what is a base64 string from which a QR Code is generated. I have been working on it, but the code errors out at the "let nsd = ..." line, with the message: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
Any help of where I am going wrong would be greatly appreciated. I am a novice when it comes to Swift and programming in general, so am finding this quite challenging. I am also don't think I am correctly converted the response into a JSON, as that is where it is first errorring out.
func qrCodeGenerator(payload : String) {
guard let response = /response as a string from SDK/ else {return}
/* convert response string to an NSData response, so as to convert to JSON in the code below */
let nsd: NSData = NSData(base64Encoded: response, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)!
var jsonResponse = JSON.null
do {
/* convert the response to a json object */
try jsonResponse = JSONSerialization.jsonObject(with: nsd as Data, options: []) as! JSON
/* enter the result array, as the base64 string is contained there */
var result = jsonResponse["result"][0]
var resqr_64 = result["qr_b64"].stringValue
print(resqr_64)
var base64string = resqr_64
/*The base64 string lies beyond the comma*/
var base64image = String(base64string.split(separator: ",")[1]) as String
var decodeString : NSData = NSData(base64Encoded: base64image, options: [])!
var decodedimage: UIImage = UIImage(data: decodeString as Data)!
QRCodeImageView.image = decodedimage
} catch {
print(error)
}
}
Any help would be greatly appreciated! Thank you so much.
if let decodedData = Data(base64Encoded: (dataDict["THUMBNAIL"] as? String)! , options: .ignoreUnknownCharacters{
self.imgThumb.image = UIImage(data: decodedData)
}
try this code to get image from base64 string :)
There are two serious issues in the code:
1) The response is most likely a regular JSON string (not base64 encoded), initializing base64 encoded Data from the string cannot work.
2) You cannot force cast the result of JSONSerialization to JSON, use the SwiftyJSON initializer.
Please try
func qrCodeGenerator(payload : String) {
guard let response = /response as a string from SDK/ else {return}
/* convert response string to an NSData response, so as to convert to JSON in the code below */
let data = Data(response.utf8)
do {
/* convert the response to a json object */
let jsonResponse = try JSON(data)
/* enter the result array, as the base64 string is contained there */
let result = jsonResponse["result"][0]
let base64string = result["qr_b64"].stringValue
print(base64string)
/*The base64 string lies beyond the comma*/
let base64image = String(base64string.split(separator: ",")[1])
let decodeString = Data(base64Encoded: base64image)!
let decodedimage = UIImage(data: decodeString)!
QRCodeImageView.image = decodedimage
} catch {
print(error)
}
}
Note: Aren't you concerned about the bunch of Variable 'xyz' was never mutated; consider changing to 'let' constant warnings? 😉

Unable to use SwiftyJSON to access JSON data

I'm trying to access some JSON data but I can't access that using swiftyJSON. I'm getting JSON response back so I'm acquiring it using alamofire. Here's the JSON:
{"groupID":"6","groupName":"Test","teacher":"teacher1
","teacherID":"13","Locations":
[{"locationID":"5","locationName":"field"},
{"locationID":"6","locationName":"34th"}],"Error":""}
I'm using print statements to debug what's wrong. Here's the code that I'm trying to use:
let json = JSON(response.result.value ?? "error")
//let jsonError = json["Error"]
print("=================<JSON RESPONSE>=================");
print(json)
print("=================</JSON RESPONSE/>=================");
self.groupID = json["groupID"].stringValue
self.groupName = json["groupName"].stringValue
self.teacherID = json["teacherID"].stringValue
let locjson = json["Locations"]
print("Entering LocJSON Loop")
print("=================<LOCJSON >=================");
print("GNAME:" + self.groupID)
print("TID: " + json["teacherID"].stringValue)
print("Locjson.stringalue: " + locjson.stringValue)
//print("LocationJSON" + json["Locations"]);
print("=================</LOCJSON/>=================");
for (key, object) in locjson {
print("In LocJSON Loop")
let locationIDVar: Int? = Int(key)
self.locations[locationIDVar!].locationID = locationIDVar!
self.locations[locationIDVar!].locationName = object.stringValue
print(self.locations[locationIDVar!].locationName)
print(object);
}
Here's the output from console that corresponds to the print statements.
=================<JSON RESPONSE>=================
{"groupID":"6","groupName":"Test","teacher":"Teacher1"
,"teacherID":"13","Locations":
[{"locationID":"5","locationName":"field"},
{"locationID":"6","locationName":"34th"}],"Error":""}
=================</JSON RESPONSE/>=================
Entering LocJSON Loop
=================<LOCJSON >=================
GNAME:
TID:
Locjson.stringalue:
=================</LOCJSON/>=================
Also, how do I get to the multiple locations that are inside 'Locations'?
The value for key Locations is an array containing dictionaries.
let locjson = json["Locations"].arrayValue
for location in locjson {
let locID = location["locationID"].stringValue
let locName = location["locationName"].stringValue
print(locID, locName)
}
In Swift 4 I'd prefer Decodable over SwiftyJSON because you can directly decode into structs.