Parse alamofire response into JSON return nil - ios

I'm trying to parse data from alamofire response. If i print all response it works good, but if i want to print specific parametr form JSON, for example "firstName" it is returning nil.
AF.request("http://localhost:5000/api/users").responseJSON(completionHandler: { (res) in
switch res.result {
case let .success(value):
let xjson : JSON = JSON(res.value)
print(xjson["firstName"].string)
case let .failure(error):
print(error)
}
})
No errors in console
Code below
AF.request("http://localhost:5000/api/users").responseJSON(completionHandler: { (res) in
switch res.result {
case let .success(value):
let xjson : JSON = JSON(res.value)
print(xjson)
print(xjson["firstName"].string)
case let .failure(error):
print(error)
}
})
returns
[
{
"dateOfBirth" : "1998-11-18T00:00:00.000Z",
"_id" : "5f6a29ed16444afd36e9fe15",
"email" : "sdasd#mail.com",
"__v" : 0,
"firstName" : "adam",
"lastName" : "kowalski",
"accountCreateDate" : "2020-09-22T16:44:29.692Z",
"userPassword" : "12345",
"userLogin" : "loginakowalski"
}
]
nil

This xjson is an Array of JSON(looks User) objects. So you need to access the array elements as below,
let xjson : JSON = JSON(res.value)
if let firstUser = xjson.array?.first {
print(firstUser["firstName"] as? String)
}
You can also put your JSON response here and get the required data types and decoding code for free.

Thanks to everyone for your help. Below is the code that returns the correct value:
AF.request("http://localhost:5000/api/users").responseJSON(completionHandler: { (res) in
switch res.result {
case let .success(value):
let xjson : JSON = JSON(res.value)
if let firstUser = xjson.array?.first {
print(firstUser["firstName"].string!)
}
case let .failure(error):
print(error)
}
})

Related

Alamofire parse JSON msg and status

I want to display the msg on UITextView using the status, but it display "Success: 200":
{ "status" : 500, "msg" : "\"Information is invalid\"" }
I'm using Swift4 in XCode10, here is my code:
import UIKit
import Alamofire
import SwiftyJSON
class VerifyAccount: UIViewController {
let verify_url = "http://192.168.43.222:3000/mobile/account_verification"
#IBOutlet weak var msgHandler: UITextView!
func postData(url: String , parameters: [String : String]) {
Alamofire.request(url, method: .post, parameters: parameters).responseJSON {
response in
if response.result.isSuccess {
let postJSON : JSON = JSON(response.result.value!)
print(postJSON)
if let status = response.response?.statusCode {
switch(status) {
case 200:
self.msgHandler.text = ("Success: \(status)")
case 500:
self.msgHandler.text = ("Invalid: \(status)")
default:
}
}
} else {
print("Error: \(String(describing: response.result.error))")
}
}
}
#IBAction func verifyBtn(_ sender: Any) {
let compare : [String : String] = ["id" : id , "fname" : fname , "lname" : lname]
postData(url: verify_url , parameters : compare)
}
}
You need to change the way how you handling your response. I've updated your code, it should work.
import UIKit
import Alamofire
import SwiftyJSON
class VerifyAccount: UIViewController {
let verify_url = "http://192.168.43.222:3000/mobile/account_verification"
#IBOutlet weak var msgHandler: UITextView!
func postData(url: String , parameters: [String : String]) {
Alamofire.request(url, method: .post, parameters: parameters).responseJSON {
response in
switch response.result {
case .success:
print("server response: \(response.value!)")
do {
if var json = try JSONSerialization.jsonObject(with: response.data!, options: []) as? [String:Any] {
// Get value by key
var message = "";
if let msg = json["msg"] as? String
{
message = msg; // your message is here, you can do anything with it, whatever you want.
}
var status = 0;
if let st = json["status"] as? Int
{
status = st;
}
}
} catch let error as NSError {
}
break
case .failure(let error):
self.delegate.APIOnError(requestCode: requestCode);
print("server error: \(error.localizedDescription)")
}
}
}
You can get a value safely (whether it's a String, Int, etc...) from your JSON object like so:
let status = postJSON["status"].int ?? 0
let message = postJSON["msg"].string ?? "No Message"
The (??) double question mark gives you the ability to provide a default value in case your parsing fails to get an Int or String
Parse your response data like
guard data _ = response.result.value as? [String: Any] else {
print("Error: \(String(describing: response.result.error))")
return
}
let message = data["msg"] as? String ?? "Unable to parse message"
if let statusCode = data["status"] as? Int {
switch statusCode {
case 200: self.msgHandler.text = ("Success: \(message)")
case 500: self.msgHandler.text = ("Invalid: \(message)")
default:self.msgHandler.text = ("Invalid status code")
}
}
You were using wrong data to parse. You can try this:
if let status = response.response?.statusCode, let message = postJSON['msg'] {
switch(status) {
case 200:
self.msgHandler.text = ("Success: \(message)")
case 500:
self.msgHandler.text = ("Invalid: \(message)")
default:
}
}

Simple getJSON() function

SwiftyJSON is an extremely useful add-on for Swift, importable via various methods (CocoaPods, Carthage, etc.) and I use it within many of my projects as they commonly require JSON files. So I wanted a nice simple function that I could call with necessary arguments and get my raw String value from my JSON file.
Step 1. We will create one protocol with one constructor method in it and Model class
protocol JSONable {
init?(parameter: JSON)
}
class Style: JSONable {
let ID :String!
let name :String!
required init(parameter: JSON) {
ID = parameter["id"].stringValue
name = parameter["name"].stringValue
}
/* JSON response format
{
"status": true,
"message": "",
"data": [
{
"id": 1,
"name": "Style 1"
},
{
"id": 2,
"name": "Style 2"
},
{
"id": 3,
"name": "Style 3"
}
]
}
*/
}
Step 2. We will create extension of JSON which will convert JSON to model class type object
extension JSON {
func to<T>(type: T?) -> Any? {
if let baseObj = type as? JSONable.Type {
if self.type == .array {
var arrObject: [Any] = []
for obj in self.arrayValue {
let object = baseObj.init(parameter: obj)
arrObject.append(object!)
}
return arrObject
} else {
let object = baseObj.init(parameter: self)
return object!
}
}
return nil
}
}
Step 3. Use code with Alamofire or other code.
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
var styles: [Style] = []
if let styleArr = json["data"].to(type: Style.self) {
styles = styleArr as! [Style]
}
print("styles: \(styles)")
case .failure(let error):
print(error)
}
}
I hope this will be useful.
Please refer to this link for more information on this.
https://github.com/SwiftyJSON/SwiftyJSON/issues/714
Here is the function I created, feel free to use it yourself (does of course require SwiftJSON to be correctly integrated within your Xcode Swift project)...
func getJSON(value: [String], fileName: String) -> String{
guard let path = Bundle.main.path(forResource: fileName, ofType: "json"),
let jsonData = NSData(contentsOfFile: path) else{
print("Couldn't find the file on disk or failed to read it")
return "ERR."
}
let jsonObject = JSON(data: jsonData as Data)
guard let jsonValue = jsonObject[value].string else{
print("FAILED to find JSON object")
return "ERR."
}
return jsonValue
}
An example usage of this function would be let myJsonValue = getJSON(value: ["people","person1"], fileName: "database") which would get the value person1 from the people group in the JSON file named database.json. So, if the database.json file looked something like this
{
"people" : {
"person1" : "Bob",
"person2" : "Steve",
"person3" : "Alan",
}
}
the function would return a value of "Bob"
Hope this is a help to anyone, or if you have any suggestions for it then please let me know! Constructive criticism appreciated always.

pull data from parsed Json with swift

I want to get my CampaignList from JsonObject which I parsed before. But it gives fatal error while it is running.
Error
"fatal error: unexpectedly found nil while unwrapping an Optional value"
self.CampaignArray = Campaigns as! NSMutableArray
The code :
var CampaignArray:NSMutableArray = []
func Get(){
let res: String = ""
let jsonObject = ["PhoneNumber": "xxxxx"]
let Jsn = JsonClass(value: jsonObject, text: res)
Alamofire.request(.POST, "http://MYURL",parameters: jsonObject,
encoding: .JSON).validate(statusCode: 200..<303)
.validate(contentType: ["application/json"])
.responseJSON { (response) in
NSLog("response = \(response)")
switch response.result {
case .Success:
guard let resultValue = response.result.value else {
NSLog("Result value in response is nil")
//completionHandler(response: nil)
return
}
let responseJSON = resultValue
print(responseJSON)
let result = Jsn.convertStringToDictionary(responseJSON as! String)!
print("result: \(result)")
let Campaigns = (result as NSDictionary)["Campaigns"]
print(Campaigns)
self.CampaignArray = Campaigns as! NSMutableArray
let notifications = (result as NSDictionary)["Notifications"]
print(notifications)
break
case .Failure(let error):
NSLog("Error result: \(error)")
// Here I call a completionHandler I wrote for the failure case
return
}
}
}
And my response Json is:
json: {"CampaignList":[
{"Bonus":"5","CampaignId":"zQUuB2RImUZlcFwt3MjLIA==","City":"34"}
{"Bonus":"3","CampaignId":"VgYWLR6eL2mMemFCPkyocA==","City":"34"}],
"MemberId":"ZBqVhLv\/c2BtMInW52qNLg==",
"NotificationList":[{"Notification":"Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?","PhoneNumber":"555555555"}]}
JSON you provide is invalid. There is lack of , in Campaigns dictionary.
Valid JSON looks like:
{
"CampaignList": [
{
"Bonus": "5",
"CampaignId": "zQUuB2RImUZlcFwt3MjLIA==",
"City": "34"
},
{
"Bonus": "3",
"CampaignId": "VgYWLR6eL2mMemFCPkyocA==",
"City": "34"
}
],
"MemberId": "ZBqVhLv/c2BtMInW52qNLg==",
"NotificationList": [
{
"Notification": "Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?",
"PhoneNumber": "555555555"
}
]
}
fatal error: unexpectedly found nil while unwrapping an Optional value
You receive this error because you try cast nil to NSDictionary object.
You have no Campaigns key in JSON you provide, so when you try to get this key from JSON you get nil. In next step you try cast this nil to NSDictionary.
Try use CampaignList key to get data you want.
let result: [String: AnyObject] = Jsn.convertStringToDictionary(responseJSON as! String)!
let campaigns: [Campaign] = result["CampaignList"] as! [Campaign]
print(Campaigns)
self.CampaignArray = campaigns
let notifications = result["NotificationList"]
print(notifications)
The same case will be with your Notifications key from JSON Dictionary.
You should also use swift types over objective-c NSDictionary and NSArray.
Try to use SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON)
This library (pod) is very simple and has detailed documentation.
Your example:
I put son file "data.json" in my project and read it. Thank Daniel Sumara for your json example correction.
if let path = NSBundle.mainBundle().pathForResource("data", ofType: "json") {
if let data = NSData(contentsOfFile: path) {
let json = JSON(data: data)
if let CampaignList = json["CampaignList"].array {
for index in 0 ..< CampaignList.count {
print("Campaign [\(index)]")
if let CampaignId = CampaignList[index]["CampaignId"].string {
print(" CampaignId: \(CampaignId)")
}
if let City = CampaignList[index]["City"].string {
print(" City: \(City)")
}
if let Bonus = CampaignList[index]["Bonus"].string {
print(" Bonus: \(Bonus)")
}
}
}
if let MemberId = json["MemberId"].string {
print("MemberId: \(MemberId)")
}
if let NotificationList = json["NotificationList"].array {
print("NotificationList")
for notification in NotificationList {
if let Notification = notification["Notification"].string {
print(" Notification: \(Notification)")
}
if let PhoneNumber = notification["PhoneNumber"].string {
print(" PhoneNumber: \(PhoneNumber)")
}
}
}
}
}
Also you can use Alamofire-SwiftyJSON (https://github.com/SwiftyJSON/Alamofire-SwiftyJSON)
P.S. you have fatal errors because you do not check if value is nil. read about "if let" expression (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html)

Trying to parse JSON in swift with swiftyJSON

The issue is i am not able to populate an array with what I thought would be correct code to parse a JSON file with swiftyJSON.
As well as I am not sure if the process at which i send the request is correct.
JSON format: this should be simplified to what it truly represents: A dictionary with a "string" key and value of an array of dictionaries. then a string key with a value of a dictionary. then a string with a value of a string which i need.
{
"string1" : [
{ "string2" : {
"string3" : "DataINeed"
}
}
]
}
my code
func downloadSecondJSONData(completed: DownloadComplete)
{
let API_ServerKey = "My API Key"
let URL_Search = "URL Address"
let urlString = "\(URL_Search)"
let url = NSURL(string: urlString)!
Alamofire.request(.GET,url).responseJSON { (response) -> Void in
switch response.result
{
case .Success:
if let value = response.result.value
{
let json = JSON(value)
if let data = json["string1"]["string2"]["string3"].string
{
self.dataArray.append(data)
}
}
case .Failure(let error):
print(error)
}
completed()
}
}
func printData()
{
print(self.dataArray.count)
}
How I am attempting to call the methods
downloadFirstJSONData { () -> () in
self.randomMethod() //data i use with the downloadFirstJSONData is required to use in the downloadSecondJSONData
self.downloadSecondJSONData({ () -> () in
self.printData() //check if data has been stored
})
}
Looks like you're not accessing the array after the first dictionary.
I guess the safe way to access the first object would be:
if let array = json["string1"].array,
let firstDict = array.first,
let data = firstDict["string2"]["string3"].string {
self.dataArray.append(data)
}
But I suppose with SwiftyJSON you can also do a variation of what you had:
if let data = json["string1"][0]["string2"]["string3"].string {
self.dataArray.append(data)
}

Loop through JSON response from Alamofire

I am using xcode 7.2 and swift 2.1.1. using Alamofire for server communication. I have a tableview that display's dynamic data.Data includes username , useremail , profilePicture etc. I Tried to implement this code from stackoverflow. But I am getting a warning message says Cast from 'JSON' to unrelated type '[Dictionary]' always fails My json response is
{
"JsonRequestBehavior" : 1,
"MaxJsonLength" : null,
"ContentType" : null,
"Data" : {
"_id" : "5658444778a7531f4c79c23d",
"Photo" : "",
"AllowSharing" : "YES",
"MemberCount" : 5,
"Users" : [
{
"_id" : "5658443478a7531f4c79c23c",
"Photo" : "",
"MembershipDate" : "0001-01-01T00:00:00",
"MiddleName" : null,
"FirstName" : "Gohan",
"LastName" : null,
"Email" : "gohan#gmail.com"
},
{
"_id" : "566ea5f1dfead62350cf0fad",
"Photo" : "",
"MembershipDate" : "0001-01-01T00:00:00",
"MiddleName" : null,
"FirstName" : null,
"LastName" : null,
"Email" : "sachin#gmail.com"
}
],
"MembershipDate" : "2015-12-14T12:03:12.819Z",
"CreatedBy" : "5658443478a7531f4c79c23c"
},
"ContentEncoding" : null,
"RecursionLimit" : null
}
How can I loop through Users in JSON response ?
EDIT as per JohnyKutty's answer I tried the same code in my Project. The code for the same is
Alamofire.request(.GET,App.AppHomeURL() + "Load_Group", parameters: ["groupid":"\(groupId)"]).responseJSON
{
response in
print("\(response.data)")
switch response.result
{
case .Success(let _data):
let jsonData = JSON(_data)
print("Admin Response : \(jsonData)")
do
{
let json = try NSJSONSerialization.JSONObjectWithData(_data as! NSData, options: .AllowFragments) as! NSDictionary
if let DataObject = json["Data"] as? NSDictionary
{
if let users = DataObject["Users"] as? [NSDictionary]
{
for user in users
{
print("User id : \(user["_id"])")
}
}
}
}
catch let error as NSError
{
print(error.localizedDescription)
}
in this line let json = try NSJSONSerialization.JSONObjectWithData(_data as! NSData, options: .AllowFragments) as! NSDictionary
At first I used "_data" and then Xcode suggested a change and it changed from _data to _data as! NSData.
Your son structure is like following
JSON(Dictionary) -> Data(Dictionary) -> Users(Array of Dictionaries). So first you should pick the Users array from raw json then iterate through it.
Since alamofire is already serializing your response, No need to use JSONSerializer again, I am updating my answer.
UPDATE
Try this code inside the case
if let DataObject = _data["Data"] as? NSDictionary {
if let Users = DataObject["Users"] as? [NSDictionary] {
for user in Users {
print(user["_id"],user["MembershipDate"],user["FirstName"],user["Email"], separator: " ", terminator: "\n")
}
}
}
Full code:
Alamofire.request(.GET,App.AppHomeURL() + "Load_Group", parameters: ["groupid":"\(groupId)"]) .responseJSON { response in
switch response.result {
case .Success(let _data):
print(_data)
if let DataObject = _data["Data"] as? NSDictionary {
if let Users = DataObject["Users"] as? [NSDictionary] {
for user in Users {
print(user["_id"],user["MembershipDate"],user["FirstName"],user["Email"], separator: " ", terminator: "\n")
}
}
}
default:
break;
}
}

Resources