How to parsed all the data in JSON? - ios

First issue I addressed
I am working on an APIService using Alamofire, I tried to print the response and the I got the data successfully, but unfortunately the data from JSON turns to nil when I parse it to the attendees Object. How can I reflect the data from json to the attendees object?
Second Issue
I solved the 1st issue, after all the debugging I had. The codes I used was written in my answer below. I parsed data from JSON going to attendees but as I checked only the first array was fetch. How can I get all the data inside the JSON? Hope you can help me. Thank you.
func getParticipants(passcode: String,
participantType: ParticipantType,
successBlock: #escaping (Attendees?) -> Void,
failureBlock: #escaping (Error) -> Void)
{
let attendeesURL = URL(string: "\(GET_PARTICIPANTS_URL)/\(passcode)/\(participantType)")
Alamofire.request(attendeesURL!, method: .get).responseJSON { (response) in
print(response)
if let error = response.error
{
failureBlock(error)
return
}
if let attendeeJSON = response.result.value as? [Dictionary<String, Any>],
let attendeeObj = attendeeJSON.first {
print(attendeeObj)
let attendees = Attendees.init(JSON: attendeeObj)
successBlock(attendees)
}
}
}
}
JSON
[
{
"event_name": "Laugh Trip",
"event_participants": [
{
"participant_id": "6f1e7fd5-6da9-4d5b-bc91-4771aeaa5235",
"employee_number": "",
"last_name": "name",
"first_name": "name",
"middle_name": "",
"display_name": "name, name ",
"department_name": "IT",
"position_name": "Application Developer",
"registered_flag": true,
"registered_datetime": "2018-07-16T14:51:57.813",
"registration_type": 1,
"delete_flag": false,
"manual_reg_flag": false,
"out_flag": true,
"out_datetime": "2018-07-16T14:54:00.000",
"classification": 1,
"others": ""
},
{
"participant_id": "6f1e7fd5-6da9-4d5b-bc91-4771aeaa5235",
"employee_number": "",
"last_name": "name",
"first_name": "name",
"middle_name": "",
"display_name": "name, name ",
"department_name": "IT",
"position_name": "Application Developer",
"registered_flag": true,
"registered_datetime": "2018-07-16T14:51:57.813",
"registration_type": 1,
"delete_flag": false,
"manual_reg_flag": false,
"out_flag": true,
"out_datetime": "2018-07-16T14:54:00.000",
"classification": 1,
"others": ""
},
]
]

Instead of using first which gets only the first item of the sequence use a loop respectively.
if let events = response.result.value as? [[String : Any]] {
for event in events {
if let eventparticipants = event["event_participants"] as? [[String : Any]] {
print(eventparticipants)
for participant in eventparticipants {
let attendees = Attendees.init(JSON: participant)
successBlock(attendees)
}
}
}
}
I recommend to decode the JSON directly into structs with Decodable

I solved my own issue. :D
Alamofire.request(attendeesURL!, method: .get).responseJSON { (response) in
print(response)
if let error = response.error
{
failureBlock(error)
return
}
if let jsonDictionary = response.result.value as? [Dictionary<String, Any>]{
if let eventparticipants = jsonDictionary.first {
print(eventparticipants)
if let partObj = eventparticipants["event_participants"] as? [[String : Any]]{
let attendeeObj = partObj.first
let attendees = Attendees.init(JSON: attendeeObj!)
successBlock(attendees)
}
}
}
}

Related

Parsin JSON directory inside another directory

Alamofire.request("https://example.com/stories.php", method: .post, parameters: parameters).validate().responseJSON { response in
switch response.result {
case .success:
if let json = response.result.value {
let json2 = JSON(json)
for (_, subJSON): (String, JSON) in json2[0]["stories"] {
if let arr = subJSON["user"].dictionary {
let title = arr["name"]?.string
let id = arr["id"]?.int
let photo = arr["picture"]?.string
let rel1 = InboxStories(title: title!, storyID: id!, photo:photo!)
cell.arrayOfRels.append(rel1)
}
}
cell.getStoryDel()
}
case .failure(_):
print("hata")
}
}
JSON output
[{
"stories": [{
"id": "s1",
"last_updated": "1582543824",
"user": {
"id": "2",
"name": "testuser",
"picture": "https:\/\/example.com\/ios\/images\/profile_pic\/116534.jpg"
},
"snaps_count": "1",
"snaps": [{
"id": "c1",
"mime_type": "image",
"url": "chttps:\/\/example.com\/ios\/stories\/image\/3434.jpg",
"last_updated": "1582543824"
}]
}],
"count": 1
}]
I am trying to reach user key of stories.
It returns nil in my code. How can I parse it?
stories is also an array, please note the []
And it's pretty confusing to name a dictionary arr 😉
if let stories = json2.array?.first?["stories"].array {
for story in stories {
if let dict = story["user"].dictionary {
let title = dict["name"]!.stringValue
let id = dict["id"]!.stringValue
let photo = dict["picture"]!.stringValue
let rel1 = InboxStories(title: title, storyID: id, photo:photo)
cell.arrayOfRels.append(rel1)
}
}
}
And consider to use Decodable. It's built-in and more comfortable than SwiftyJSON

Create extension in Swift 5 for Dictonary[String:Any]

I want to create extension for Dictionary [String:Any] which is received from API Response.
Right Now I am doing below way
I have created func getDataFromJson this is working fine, Please let me know how to do that.
func getDataFromJson(json: AnyObject) -> Data?{
do {
print("json = \(json)")
return try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil;
}
This is my response and I want to "data" to Data
{
"status": true,
"message": "Country List",
"data": [
{
"id": 1,
"name": “ABC”,
"code": "A",
"phone_code": "+91”,
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": “ZYX”,
"code": “Z”,
"phone_code": "+1”,
"flag": "country-flags/-shiny.png"
}
]
}
I want to get data this way jsonResponse["data"].retriveData()
Here is a simple function that encodes the dictionary, the function throws any error so it can be properly handled. Since JSONSerialization.data(withJSONObject: takes an Any parameter this function can also be implemented for an array etc
extension Dictionary {
func retriveData() throws -> Data {
return try JSONSerialization.data(withJSONObject: self)
}
}
Simple example
let dict = ["abc": 123, "def": 456]
do {
let data = try dict.retriveData()
let result = try JSONDecoder().decode([String:Int].self, from:data)
print(result)
} catch {
print(error)
}
Another way is to use Result if you're on Swift 5 (shortened after comment from vadian)
extension Dictionary {
func retriveData() -> Result<Data, Error> {
return Result { try JSONSerialization.data(withJSONObject: self) }
}
}
and an example
let result = try dict.retriveData()
switch result {
case .success(let data):
let dictionary = try JSONDecoder().decode([String:Int].self, from:data)
print(dictionary)
case .failure(let error):
print(error)
}
a copy of your function transposed to an extension can be
extension Dictionary {
func retriveData() -> Data? {
do {
return try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil
}
}
Correct json
{
"status": true,
"message": "Country List",
"data": [
{
"id": 1,
"name": "ABC",
"code": "A",
"phone_code": "+91",
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": "ZYX",
"code": "Z",
"phone_code": "+1",
"flag": "country-flags/-shiny.png"
}
]
}
Model
struct Datum: Codable {
let id: Int
let name, code, phoneCode, flag: String
}
Decoding data only
let str = """
{
"status": true,
"message": "Country List",
"data": [{
"id": 1,
"name": "ABC",
"code": "A",
"phone_code": "+91",
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": "ZYX",
"code": "Z",
"phone_code": "+1",
"flag": "country-flags/-shiny.png"
}
]
}
"""
do {
let dic = try JSONSerialization.jsonObject(with: Data(str.utf8)) as! [String:Any]
let content = try JSONSerialization.data(withJSONObject: dic["data"])
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let res = try dec.decode([Datum].self, from: content)
print(res)
}
catch {
print(error)
}
Please try this
// Response Dictionary
let jsonResponse : [String:Any] = ["data":["key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":"value4"]]
// check dictionary contains value for key "data"
if let dataDict = jsonResponse["data"] as? [String:Any] {
// convert dictionary to data
let jsonData = dataDict.retriveData()
print("Json Data :- ", jsonData != nil ? "Success" : "Data is nil")
}
// Dictionary exxtension for converting dictionary to json data
extension Dictionary {
func retriveData() -> Data? {
do {
print("json = \(self)")
return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil;
}
}

Cannot update data in API using .PUT request in Alamofire

I am creating an Event app where in the user should tap Check In Button to register for the event. registered_flag : false will be true and registered_type: 0 will be 1 once the user tapped the button. But as I build and run the app, error appeared that says
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error
Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character
0." UserInfo={NSDebugDescription=Invalid value around character 0.})).
I am not really confident regarding the content of my codes in my APIService. Hope someone will help me to correct my codes so I could build and run my app successfully. Thank you so much.
application/json that needs to be updated which inside event_participant
{
"registered_flag": false,
"registration_type": 0
}
event_participant
"event_participants": [
{
"participant_id": "70984656-92bc-4c36-9314-2c741f068523",
"employee_number": null,
"last_name": "Surname",
"first_name": "FirstName",
"middle_name": null,
"display_name": "Surname, FirstName ",
"department_name": "Department",
"position_name": "Developer",
"registered_flag": false,
"registered_datetime": "2018-09-13T08:54:40.150",
"registration_type": 0,
"delete_flag": false,
"manual_reg_flag": false,
"out_flag": false,
"out_datetime": null,
"classification": 6,
"others": "Guest"
}
}
API Service using PUT request in Alamofire
func updateParticipant(updateType: UpdateParticipantType,
participantID: String,
completionHandler: #escaping(([Attendee]?, Error?) -> Void)) {
let updateParticipantURL = URL(string: "\(REGISTER_PARTICIPANT_URL)/\(updateType)/\(participantID)")
let headers: HTTPHeaders = [
"Content-Type": "application/json"
]
let parameters: Parameters = [
"registered_flag": false,
"registration_type": 0
]
Alamofire.request(updateParticipantURL!, method: .put, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
switch response.result {
case .success:
print("Done")
if let jsonArray = response.result.value as? [[String : Any]] {
for anItem in jsonArray {
if let eventparticipant = anItem["event_participants"] as? [[String : Any]] {
var extractedAttendee = [Attendee]()
for participant in eventparticipant{
print(participant)
let success = Attendee.init(JSON: participant)
extractedAttendee.append(success!)
}
completionHandler(extractedAttendee, nil)
}
}
}
case .failure(let error):
completionHandler(nil, error)
}
}
}
Struct for Attendee
struct Attendee: Decodable {
let id: String
let employeeNumber: String?
let lastName: String
let firstName: String
let middleName: String
let displayName: String
let department: String
let position: String
let registeredFlag: Bool
let registeredDateTime: Date?
let registrationType: Int
let deleteFlag: Bool
let manualFlag: Bool
let outFlag: Bool
let outDateTime: Date?
let classification: Int?
let others: String?
postman response

How to handle JSON response with nil using guard in Swift

I just want to ask how to handle JSON return with null values in Swift.
I used guard for unwrapping the values, but if the JSON has a null value like in the example below, guard will not be executed
I also want to know proper way of using a guard. Is it okay to use multiple conditions in one guard? Like in my sample code below?
{
"error_code": "0",
"error_description": [],
"status": true,
"results": {
"id": 25,
"email": "jaundelacruz#yahoo.com",
"created_at": "2016-12-10T15:54:03.779Z",
"updated_at": "2016-12-15T06:41:49.432Z",
"first_name": "Juan",
"last_name": "Cruz",
"middle_name": "Dela",
"nickname": "joe",
"option_nickname": null,
"age": 24,
"gender": "Male",
"mobile_number": "639959283721",
"photo_url": {
"url": null
},
"school": "University of the Philippines",
"user_address": null,
"city": "Quezon City",
"country": null,
"longtitude": 121.0621301,
"latitude": 14.5832954,
"facebook_user_id": null,
"device_token": null,
"token": "YrxVEWUMYxieFy7PEsAn",
"is_sent": false,
"show_nickname": false
},
"error": []
}
Here's my code:
func UserLogin(facebookID: String) -> Void {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let urlString = Constants.baseURL + Constants.apiURL + Constants.loginUrl
let params:Dictionary<String, AnyObject> = [
"facebook_id": facebookID as AnyObject
]
Alamofire.request(urlString, method: .post, parameters: params, encoding: JSONEncoding.default)
.validate()
.responseJSON { response in
switch response.result {
case .success:
let userjson = JSON(data: response.data!)
let results = userjson["results"].dictionaryValue
guard let auth_token = results["token"]?.string,
let userid = results["id"]?.int,
let firstname = results["first_name"]?.string,
let lastname = results["last_name"]?.string,
let nickname = results["nickname"]?.string,
let city = results["city"]?.string,
let photo = results["photo_url"]?["url"]else{
//nil
return
}
//The Process will not continue from here if the JSON response has a null value)
self.userdefault.saveUserToken(authToken: auth_token)
self.userdefault.setUserID(userID: userid)
self.userdefault.setuserFirstName(userFName: firstname)
self.userdefault.setuserLastName(userLName: lastname)
self.userdefault.setuserNickName(userNName: nickname)
self.userdefault.setuserCity(userCity: city)
self.GotoMainNavigation()
case .failure(let error):
print("susb \(error)")
self.getFacebookInfo()
}
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
Thank you
Your guard expression is perfectly fine and filters all null values except in the last line. Assuming the url is also a string you have to check
let photo = results["photo_url"]?["url"]?.string ...
but consider that the guard expression will only be evaluated to true if all optional bindings succeed.
For example if the photo value is supposed to be optional put it after the guard expression and use the nil coalescing operator:
let photo = results["photo_url"]?["url"]?.string ?? ""
data = {
results = {
resultsData = (
{
a = "A";
b = "B";
c = "C":
}
);
};
};
guard is a new conditional statement that requires execution to exit the current block if the condition isn’t met. Any new optional bindings created in a guard statement’s condition are available for the rest of the function or block, and the mandatory else must exit the current scope, by using return to leave a function, continue or break within a loop, or a #noreturn function
guard let data = response["data"] as? [String:AnyObject],let resultsObj = response["results"] as? [String:AnyObject],let resultsData = results["resultsData"] as? [String:AnyObject] else{
return
}

NSJSONSerialization return nil with a valid json

I try to parse a response which return a valid JSON with NSJSonSerialization. But it returns nil with no error. It works with another JSON response.
I did some search, and this could be a problem with the encoding of the JSON. I don't know how to solve it. Any idea ?
let url: NSURL = NSURL(string: urlPath)!
self.searchRequest = NSMutableURLRequest(URL: url)
if let searchRequest = self.searchRequest {
searchRequest.HTTPMethod = "GET"
let authString : String = SNCF.APIKey + ":" + ""
let authData : NSData = authString.dataUsingEncoding(NSASCIIStringEncoding)!
let authValue : String = "Basic " + authData.base64EncodedStringWithOptions(.EncodingEndLineWithCarriageReturn)
searchRequest.setValue(authValue, forHTTPHeaderField: "Authorization")
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(searchRequest, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
//HERE JSONRESULT WILL BE NIL
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String: [AnyObject]] {
print("ASynchronous\(jsonResult)")
if let places = jsonResult["stop_areas"] as? [[String:AnyObject]]{
for placeDictionary in places {
if let labelText = placeDictionary["label"] as? String {
self.resultDatasource.append(labelText)
}
}
self.resultTableView.reloadData()
}
}
//HERE NO ERROR IS CATCHED
} catch let error as NSError {
print(error.localizedDescription)
}
})
Piece of my json response :
{
"disruptions": [],
"pagination": {
"start_page": 0,
"items_on_page": 100,
"items_per_page": 100,
"total_result": 3053
},
"stop_areas": [
{
"codes": [
{
"type": "CR-CI-CH",
"value": "0080-251967-BV"
}
],
"name": "gare de Perl",
"links": [],
"coord": {
"lat": "0",
"lon": "0"
},
"label": "gare de Perl",
"timezone": "Europe/Paris",
"id": "stop_area:OCE:SA:80251967"
},
{
...
},
//stop_areas dictionaries object...
], //end stop_areas array of dictionaries
"links": [
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas/{stop_areas.id}",
"type": "stop_areas",
"rel": "stop_areas",
"templated": true
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas?start_page=1",
"type": "next",
"templated": false
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas?start_page=30.52",
"type": "last",
"templated": false
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas",
"type": "first",
"templated": false
}
],
"feed_publishers": [
{
"url": "",
"id": "sncf",
"license": "",
"name": ""
}
]
}
The type of the JSON is [String: AnyObject] not [String: [AnyObject]]
I think this is the problem:
as? [String: [AnyObject]]
Try to remove the cast. If your JSON is correct and has no validation errors, the dictionary you get probably has the key value of type Any. You can try to use the dictionary by only casting the value keys you want:
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: nil) {
print("ASynchronous\(jsonResult)")
if let places = jsonResult["stop_areas"] as? [[String:AnyObject]] {
...
}
}
Try This
do {
if let jsonResult: Dictionary = try NSJSONSerialization.JSONObjectWithData(self.mutableData, options: NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject>
{
// print("get Read messages == \(jsonResult)");
if ((jsonResult["Warning"]) != nil)
{
let error_by_wc: NSString = jsonResult["Warning"] as! String
//print("results == \(error_by_wc)");
// printMessage("\(error_by_wc)")
JLToast.makeText("\(error_by_wc)").show()
}else if((jsonResult["Error"]) != nil)
{
let error_by_wc: NSString = jsonResult["Error"] as! String
// print("results == \(error_by_wc)");
// printMessage("\(error_by_wc)")
JLToast.makeText("\(error_by_wc)").show()
}
else
{
// read message s
}
} catch {
print(error)
}
If Data is Array Type Use this code
do {
if let jsonResult:NSArray = try NSJSONSerialization.JSONObjectWithData(self.mutableData, options: .MutableContainers) as? NSArray {
//print(jsonResult)
aDataBase.insertFromUserImage(jsonResult)
connection_allMEssages()
}else
{
//print("not data found")
BProgressHUD.dismissHUD(0)
}
} catch {
print(error)
BProgressHUD.dismissHUD(0)
}

Resources