Error while parsing JSON data received via Alamofire (Swift) - ios

I'm working with a non-profit organisation to help them develop a mobile application for their website (so they provided me with the backend services, etc)
Their login PHP service accepts data in JSON, and returns a true or false value in the form of JSON data, but I'm having trouble processing the response in Swift. I'm using Alamofire to connect to the HTTP service.
I'm attaching my code and the exception message I'm receiving below, would really appreciate some help
func authenticateUser (un: String, pw: String) -> Bool
{
var checker = false
let jsonDict : [String: String] = ["volunteer_email": un, "volunteer_pass": pw]
Alamofire.request("www.sampleurl.com/login.php", method: .post, parameters: jsonDict, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print (response.result.value)
let resp = response.result.value as! NSDictionary
let results = resp["status"] as! [[String:Any]]
//Change the boolean value of checker based on the value of the results constant
print (results)
}
break
case .failure(_):
print(response.result.error)
break
}
}
return checker;
}
Log:
Optional(<__NSSingleObjectArrayI 0x600000009b50>( {
status = false; } ) ) Could not cast value of type '__NSSingleObjectArrayI' (0x10e28c528) to 'NSDictionary'
(0x10e28d1a8). 2018-05-09 12:13:00.177091+0530 TestApp1 [16680:817883]
Could not cast value of type '__NSSingleObjectArrayI' (0x10e28c528) to
'NSDictionary' (0x10e28d1a8). (lldb)
Log for response.result.value:
Note: "status":"false"/"true" is the output from the web service
Optional(<__NSSingleObjectArrayI 0x60400001b160>(
{
status = false;
}
))
Note: I did some research and I understood what the NSSingleObjectArray is and what causes it, but I'm stuck here as the service passes back only a single JSON value to my app. Is there any way to handle this without requesting the organisation to change their code? Logically, shouldn't I be able to cast the response into an NSDictionary regardless of its size?
Also, the reason why I've specified that the returned data can be of type any, is because I ran into an issue that can be found here:
Other StackOverflow question
Thanks so much in advance :)

Since you're using .responseJSON of Alamofire, you should make use of Alamofire's parameterized enums. It provides the json object in .success. So doing case .success(_) is wasteful.
Go ahead with this and no need of typecasting response.result.value at all.
Alamofire
.request("www.sampleurl.com/login.php",
method: .post,
parameters: jsonDict,
encoding: JSONEncoding.default,
headers: nil)
.responseJSON { (response) in
switch(response.result) {
case .success(let responseJSON):
print(responseJSON)
/*
As an improvement:
To obtain an easy-access object, convert responseJSON to either a:
1. Codable model:
let model = JSONDecoder().decode(SomeModel.self,
from: responseJSONData)
2. SwiftyJSON object: (available on GitHub)
let json = JSON(responseJSON)
Doing so will basically make accessing the inner elements easier.
*/...
case .failure(let error):
print(error)
}
}
BTW, just FYI: the response is an array of dictionaries, not a dictionary of array of dictionaries.

Use NSArray instead of NSDictionary
func authenticateUser (un: String, pw: String) -> Bool{
var checker = false
let jsonDict : [String: String] = ["volunteer_email": un, "volunteer_pass": pw]
Alamofire.request("www.sampleurl.com/login.php", method: .post, parameters: jsonDict, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print (response.result.value)
let resp = response.result.value as! NSArray
let results = resp["status"] as! [[String:Any]]
//Change the boolean value of checker based on the value of the results constant
print (results)
}
break
case .failure(_):
print(response.result.error)
break
}
}
return checker;
}

Related

getting data from AF.Request response

I need the data from the json response from my Post request call using Alamofire but I cannot access that data for some reason
I tried following along with Alamofire github documentation along with this post get data from AF responseJSON. but neither have helped me.
AF.request("https://mbd.cookcountysupernetwork.com/ap/swift_math_get.asp", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
print("floop")
}
This is what I see when the code runs
success({
Operand = (
{
A = 12;
},
{
B = 25;
}
);
Operation = Multiply;
Result = 300;
})
so I know the json is there, i just need to access the "Result = 300" so I can set a text box to say "300". but I tried many different methods and I cannot access the information I need from response. Also i do not have a response.result.value which is what almost every post I see about this says to use.
You can access the Result value as,
AF.request("https://mbd.cookcountysupernetwork.com/ap/swift_math_get.asp", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success(let value):
if let json = value as? [String: Any] {
print(json["Result"] as? Int)
}
case .failure(let error):
print(error)
}
}

How to access alamofire response

I'm new to iOS and I have some Swift code in app that's supposed to switch cases depending on the error message that I receive from the server. The message is wrapped and I'm having trouble getting to it. Here's the code
func sendAlamofireRequest(submissionURL: URL, parameters: Parameters, chosenTracker: String) -> String {
var outputMessage = ""
Alamofire.request(submissionURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseString() {
response in
switch response.result {
case .success:
print("Validation Successful...\(String(describing: response.value))")
print("response value: \(String(response.value!))")
switch response.value {
case "error_none"?:
outputMessage = "No matching Group Code. If you are having trouble, please go to \nhttps://app.phillyscientists.com"
break
case "error_tooManyIDs"?:
outputMessage = "Error, please contact developer."
break
case "error_noGroupIDReceived"?:
outputMessage = "Try Again."
break
default:
let JSONResponse : JSON = JSON.init(parseJSON: response.result.value!)
//uncomment this section for debugging
// print("=================<JSON RESP>=================");
// print(JSONResponse)
// print("=================</JSON RESP/>=================");
//
let teacherNameGot = self.parseJSONData(json: JSONResponse, trackerValuePassed: chosenTracker)
self.saveJSONDataToUserDefaults(teacher: teacherNameGot)
// outputMessage = "Logged In Successfully!"
break
}
case .failure(let error):
outputMessage = String(error.localizedDescription)
print(outputMessage)
}
}
return outputMessage
}
Here's the output from console:
Validation Successful...Optional("{\"Error\":\"error_none\"}")
response value: Optional("{\"Error\":\"error_none\"}")
How do I get to the value so that the switch case actually starts working?
Thanks!
you can use Alamofire method .responseJSON which will give you an http object that has several attributes like request and response. Take this code as an example:
Alamofire.request("https://your-service-url.com/api", method: .post, parameters: paremeters, encoding: JSONEncoding.default, headers: headers).responseJSON{ (data) in
guard let statusCode = data.response?.statusCode, statusCode == 200, let result = data.result.value as? [[String: Any]] else{
print("Error with HTTP status \(data.response?.statusCode ?? 0)")
return
}
var events : [Event] = []
result.forEach({ (rawEvent) in
events.append(Event(from: rawEvent))
})
handler(events, statusCode)
}
Notice how I play there with the objects that .responseJSON provides, and how I get the resulting array from the service by accessing data.result.value (that being said this will depend on the data structure of your service response)
It seems that the output is in Json, so i'll need to map it into an object(or class,whatever you call it). If you think its not worth it, you can convert it into an Dictionary, i think it will work as well
#Gustavo caiafa is right, Mapping it to JSON did the trick. Here's the code for anyone who gets stuck on something similar:
Alamofire.request(submissionURL, method: .post, parameters: parameters, encoding: JSONEncoding.default).validate().responseString() { (response) in
let outputResponseJSON : JSON = JSON.init(parseJSON: response.result.value!)
let outputResponseText = JSON(outputResponseJSON)["Error"].stringValue
switch response.result {
case .success:
print("Validation Successful...\(String(describing: response.value))")
print("response value: \(String(describing: String(outputResponseText)))")
switch outputResponseText {
case "error_none":
outputMessage = "No matching Group Code. If you are having trouble, please go to \nhttps://app.phillyscientists.com"
print(outputMessage)
break
case "error_tooManyIDs":
outputMessage = "Error, please contact developer."
print(outputMessage)
break
case "error_noGroupIDReceived":
outputMessage = "Try Again."
print(outputMessage)
break
default:
let JSONResponse : JSON = JSON.init(parseJSON: response.result.value!)
The answer is using SwiftyJSON for the outputResponseJSON and outputResponseText values.

Assigning a long JSON response to Dictionary produces a Thread error

When trying to assign a long JSON response to a Dictionary, I get either
nil
or
Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Assigning a short response works fine. Here is my code
func getUserInfo() {
let access_token : String = accessToken_json_response["access_token"] ?? "empty"
if access_token != "empty" {
Alamofire.request("https://api.github.com/user?access_token=\(access_token)").responseJSON { response in
if let json = response.result.value {
print(json) //The JSON prints, but takes more than a second to do so.
self.getUser_json_response = json as? Dictionary<String, String> //This produces the thread error when the response is long.
print(self.getUser_json_response) //This either prints nil, or a thread error produces in the previous instruction
}
}
}
}
First of all you are casting to an optional dictionary so it should be conditional binding i.e:
if let unwrappedJson = json as? ....
Second, you should cast to [String : Any] i.e:
if let unwrappedJson = json as? [String : Any]
You have to serialise the response into json and then you can use it as dictionary.
eg: let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
then print this json
Or
Use this link, this is latest update from apple to code and encode json response according to your class or model.
Automatic JSON serialization and deserialization of objects in Swift
may this help..
Alamofire.request(UrlStr, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil)
.validate()
.responseJSON { response in
switch response.result {
case .success:
if let JSON = response.result.value {
print("JSON: \(JSON)")
let jsonResponse = (JSON as? [String:Any]) ?? [String:Any]()
print("jsonResponse: \(jsonResponse)")
}
case .failure(let error):
print(error.localizedDescription)
}
}

"Type 'Any' has no subscript members" error on Alamofire 4.0

I am using Alamofire 4.0 with Swift 3.0 and I am using the following code to parse the JSON:
Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let JSON = response.result.value{
print(JSON)
//print(JSON["name"])
//print(JSON["age"])
}
break
case .failure(_):
print("There is an error")
break
}
}
And it gives me the following response:
(
{
Name = "Peter";
Age = "18";
}
)
The problem is that I could not access to that values (Name and Age) because when I try to do JSON["name"] I am getting the following error:
Type 'Any' has no subscript members
I also have tried adding as? [String: Any] as this question suggest: Alamofire fire variable type has no subscript members and this other one also suggest: Type Any has no subscript members Error in Swift 3.0? but any response is giving to me when I use it.
If I use:
case .success(_):
if let JSON = response.result.value as? [String: Any]{
print(JSON)
print(JSON["TitularEmail"] as! String)
}
break
No errors are shown neither in Xcode or in the console of Xcode. Instead, no response is given.
How can I solve this error on a proper way? It is ok, with the solution before I am not getting any error but I am not getting any response also so it does not fix it at all.
Thanks in advance!
Try below code:
Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let JSON = response.result.value as! [[String : Any]]!{
print("JSON: \(JSON)")
let dic = JSON[0] as [String:AnyObject]!
print("TitularEmail : ",dic?["TitularEmail"])
}
break
case .failure(_):
print("There is an error")
break
}
}

Using third party library data not come in proper json form

i am new in iOS developer . and i just want to ask that when i attached third party library Alamofire using get method the data is coming but not in proper Json form,the key value comes null of each identity..please
help me here is my code:
let headers = ["Authorization":"","Accept": "application/json"]
Alamofire.request(.GET,requestString,headers:headers,encoding: .JSON)
.responseJSON { response in
print(response)
print(response.request)
Try this.
Alamofire.request(.GET, url, parameters: parameter as? [String : AnyObject]).responseJSON { (response: Response<AnyObject, NSError>) in
if error == nil {
print(response.result.value)
}
}
When you call responseJSON, it parses the JSON for you. So, if the JSON was an array of dictionaries (as shown by one of your other questions), then the response.result.value would not contain that raw JSON, but rather a nested structure of arrays and dictionaries. You can retrieve this data by unwrapping it (e.g. with if let or guard let):
Alamofire.request(requestString, headers: headers)
.responseJSON { response in
guard let dictionaries = response.result.value as? [[String: AnyObject]] else {
print(response.result.error)
return
}
// do something with the array of dictionaries, e.g. to show the names
for dictionary in dictionaries {
if let name = dictionary["name"] as? String {
print(name)
} else {
print("Name not found")
}
}
}

Resources