Repeated values in UITable cells from api json - json

After I do http call from api I get json file then I loop through it to get specific values:
if let value: AnyObject = response.result.value as AnyObject? {
let json = JSON(value)
for (key, subJson) in json {
let drivers = subJson["driver"]
for (key, subJson) in drivers {
let status = subJson["status"].stringValue
let date = subJson["created_at"].stringValue
let name = subJson["name"].stringValue
let pivot = subJson["pivot"]
for (key, subJson) in subJson["pivot"] {
let type = pivot["type"].stringValue
let data = Driverj(name: name, status: status, created_at: date)
self.data.append(data)
}
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
}
}
in a separate file I connect the values with objects:
class DriverC: UITableViewCell {
#IBOutlet weak var status : UILabel!
#IBOutlet weak var date : UILabel!
#IBOutlet weak var job : UILabel!
#IBOutlet weak var update : UILabel!
}
And in another file I have the data saved :
import Foundation
import ObjectMapper
class Driverj : Mappable {
var status : String?
var name : String?
var created_at : String?
required init?(map: Map) {
}
required init(name: String , status : String , created_at : String ) {
self.status = status
self.name = name
self.created_at = created_at
}
func mapping(map: Map) {
status <- map["status"]
name <- map["name"]
created_at <- map["created_at"]
}
}
And finally here is how it's displayed
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DriverCell", for: indexPath) as! DriverC
let entry = data[indexPath.row]
cell.date.text = entry.date
cell.job.text = entry.job
cell.status.text = entry.status
cell.update.text = entry.name
return cell
}
My question is when I run my project I get three cells with the same data repeated. Why ?
the json files :
[
{
"id": 4,
"name": null,
"email": "5#5.com",
"status": 0,
"confirmed": false,
"street": "street ",
"niehgborhood": "North",
"city": "Sf",
"national_id": "1009090",
"phone": "9000",
"size_of_house": null,
"created_at": "2016-12-04 13:55:52",
"updated_at": "2017-03-08 14:03:44",
"deleted_at": null,
"driver": [
{
"name": "unknown",
"age": "25",
"Smoker": "No",
"language": "English",
"religion": "Muslim",
"created_at": null,
"updated_at": "2017-03-08 13:48:55",
"status": "تم",
"pic": "http://localhost:8000/images/1488714520.jpg",
"id": 1,
"pivot": {
"user_id": 4,
"driver_id": 1,
"type": "driver"
}
},
{
"name": "Jae",
"age": "30",
"Smoker": "No",
"language": "English",
"religion": "Muslim ",
"created_at": "2017-02-28 09:36:15",
"updated_at": "2017-03-08 08:46:06",
"status": "ok",
"pic": "http://localhost:8000/images/1488714520.jpg",
"id": 2,
"pivot": {
"user_id": 4,
"driver_id": 2,
"type": "driver"

Related

How to parse this type of data to a JSON in Swift?

I have called an API to get all holidays in a year, it came out a Json type. But I only can extract it like below (it is one of many elements of "items")
"items": [
{
"kind": "calendar#event",
"etag": "\"3235567993214000\"",
"id": "20200101_1814eggq09ims8ge9pine82pclgn49rj41262u9a00oe83po05002i01",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=MjAyMDAxMDFfMTgxNGVnZ3EwOWltczhnZTlwaW5lODJwY2xnbjQ5cmo0MTI2MnU5YTAwb2U4M3BvMDUwMDJpMDEgZW4udWsjaG9saWRheUB2",
"created": "2021-04-07T08:26:36.000Z",
"updated": "2021-04-07T08:26:36.607Z",
"summary": "New Year's Day",
"creator": {
"email": "en.uk#holiday#group.v.calendar.google.com",
"displayName": "Holidays in United Kingdom",
"self": true
},
"organizer": {
"email": "en.uk#holiday#group.v.calendar.google.com",
"displayName": "Holidays in United Kingdom",
"self": true
},
"start": {
"date": "2020-01-01"
},
"end": {
"date": "2020-01-02"
},
"transparency": "transparent",
"visibility": "public",
"iCalUID": "20200101_1814eggq09ims8ge9pine82pclgn49rj41262u9a00oe83po05002i01#google.com",
"sequence": 0,
"eventType": "default"
},
{
"kind": "calendar#event",
"etag": "\"3235567993214000\"",
"id": "20200412_1814eggq09ims8gd8lgn6t35e8g56tbechgniag063i0ue048064g0g",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=MjAyMDA0MTJfMTgxNGVnZ3EwOWltczhnZDhsZ242dDM1ZThnNTZ0YmVjaGduaWFnMDYzaTB1ZTA0ODA2NGcwZyBlbi51ayNob2xpZGF5QHY",
"created": "2021-04-07T08:26:36.000Z",
"updated": "2021-04-07T08:26:36.607Z",
"summary": "Easter Sunday",
"creator": {
"email": "en.uk#holiday#group.v.calendar.google.com",
"displayName": "Holidays in United Kingdom",
"self": true
},
"organizer": {
"email": "en.uk#holiday#group.v.calendar.google.com",
"displayName": "Holidays in United Kingdom",
"self": true
},
"start": {
"date": "2020-04-12"
},
"end": {
"date": "2020-04-13"
},
"transparency": "transparent",
"visibility": "public",
"iCalUID": "20200412_1814eggq09ims8gd8lgn6t35e8g56tbechgniag063i0ue048064g0g#google.com",
"sequence": 0,
"eventType": "default"
}
I try to get the value in key "start" and key "summary" but I can't.
Xcode told me that "items" is a __NSArrayI type.
What I've tried so far is create a class simple like this (just use to try first, so I didn't make all variable)
class API_Info {
var kind: String?
var etag: String?
var id: String?
var status: String?
var htmlLink: String?
var created: String?
var updated: String?
var summary: String?
init(items: [String:Any]){
self.kind = items["kind"] as? String
self.etag = items["etag"] as? String
self.id = items["id"] as? String
self.status = items["status"] as? String
self.htmlLink = items["htmlLink"] as? String
self.created = items["created"] as? String
self.updated = items["updated"] as? String
self.summary = items["summary"] as? String
}
}
And I parse like this:
guard let items = json!["items"]! as? [API_Info] else{
print("null")
return
}
In this way, else statement was run.
What am I doing wrong, and how can I get the data I want?
Thanks in advance.
Codable is the solution here. Below is the struct I used rather than your class
struct ApiInfo: Codable {
let kind: String
let etag: String
let id: String
let status: String
let htmlLink: String
let created: Date
let updated: Date
let summary: String
}
Then I created a root type to hold the array
struct Result: Codable {
let items: [ApiInfo]
}
And then the decoding
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
do {
let result = try decoder.decode(Result.self, from: data)
print(result.items)
} catch {
print(error)
}
Notice that the data values are decoded to Date objects.
Optionally you can skip the root type and decode as a dictionary
do {
let items = try decoder.decode([String: [ApiInfo]].self, from: data)
if let values = items["items"] {
print(values)
}
} catch {
print(error)
}

Parse data using Alamofire and SwiftyJson

My JSON -
"documents": {
"driver": [
{
"id": 1,
"name": "Driving Licence",
"type": "DRIVER",
"provider_document": {
"id": 9,
"provider_id": 165,
"document_id": "1",
"url": "https://boucompany.com/storage/provider/documents/b92cf551a62b6b8c183997b41b9543c6.jpeg",
"unique_id": null,
"status": "ACTIVE",
"expires_at": null,
"created_at": "2019-04-26 19:05:58",
"updated_at": "2019-04-27 06:37:56"
}
},
{
"id": 2,
"name": "Bank Passbook",
"type": "DRIVER",
"provider_document": null
},
{
"id": 3,
"name": "Joining Form",
"type": "DRIVER",
"provider_document": null
},
{
"id": 4,
"name": "Work Permit",
"type": "DRIVER",
"provider_document": null
},
{
"id": 8,
"name": "Test Document",
"type": "DRIVER",
"provider_document": null
},
{
"id": 9,
"name": "NID Card",
"type": "DRIVER",
"provider_document": null
},
{
"id": 10,
"name": "Matrícula",
"type": "DRIVER",
"provider_document": null
}
],
I want to parse the url name.I have used Alamofire and SwiftyJson in my project. So far i have tried -
self.documentsDriver = json["documents"]["driver"][0]["provider_document"]["url"].stringValue
How can i print the value or "url" using swiftyjson
You can use Encodable to parse this response as below,
struct Response: Codable {
let documents: Documents
}
struct Documents: Codable {
let driver: [Driver]
}
struct Driver: Codable {
let id: Int
let name, type: String
let providerDocument: ProviderDocument?
enum CodingKeys: String, CodingKey {
case id, name, type
case providerDocument = "provider_document"
}
}
struct ProviderDocument: Codable {
let id, providerID: Int
let documentID: String
let url: String
let status: String
let createdAt, updatedAt: String
enum CodingKeys: String, CodingKey {
case id
case providerID = "provider_id"
case documentID = "document_id"
case url
case status
case createdAt = "created_at"
case updatedAt = "updated_at"
}
}
To parse the response,
let jsonData = Data() // Your API response data.
let response = try? JSONDecoder().decode(Response.self, from: jsonData)
response.documents.driver.forEach { driver in
print(driver.providerDocument?.url)
}
Parse JSON data using SwiftyJSON
func convertJSONToDriverModel(json: JSON) {
if let driver = json["documents"]["driver"].array {
for driverJson in driver {
let driverObj = convertToDriverJSONModel(json: driverJson)
print(driverObj)
}
}
}
func convertToDriverJSONModel(json: JSON) {
let name = json["name"].string ?? ""
if let providerDetails = json["provider_document"].dictionary {
let url = convertToProductDetailsJSONModel(json: JSON(providerDetails))
print("URL is: \(url)")
}
}
// Method to parse data inside provider_document (Here I have parsed only url)
func convertToProviderDocumentJSONModel(json: JSON) -> String {
let url = json["url"].string ?? ""
return url
}

Fill TableSection from Json Response in Swift

How to Populate TableSections with from this JSON Response.
I have implemented the design like the dropdown and having one prototype cell with two labels side by side inside it. below is the structure of my design
StudentDetailsSection V(button)
Father'sDetailsSection V(button)
Mother'sDeatilsSection V(button)
I am also attaching the screenshot of my design
My JSON Response is in structure.
{
"Student_Details":
[
{
"Student_ID": 1,
"School_ID": 1,
"FirstName": "Ammu",
"LastName": "Gopal",
"Date_Of_Birth": "2017-08-05T00:00:00",
"Gender": 1,
"Class": " LKG ",
"Section": "A",
"Mother_Tongue": "Tamil",
"Blood_Group": 1,
"Place_Of_Birth": "Chennai",
"Caste": 1,
"Religion": 1,
"Special_Person": 1,
"Languages_Known": "English,Tamil,Hindi",
"Distance_From_Residence_To_School": "11",
"Nationality": "Indian",
"Mode_Of_Transport": "School Transport",
"RTE": null,
"StudentStatus": 1,
"AppliedStatus": null,
"IsDeleted": null,
"Father_Name": "Kannan",
"Father_Mobile": "9845245254",
"Father_Email": "kannan#gmail.com",
"Father_Education": "Bsc",
"Father_Occupation": "Self-employer",
"Father_Name_Of_The_Organisation": "Bussiness",
"Father_Designation": "Self-Employer",
"Father_Annual_Income": "200000",
"Father_Office_Or_Business_Address": null,
"Mother_Name": "Mathi",
"Mother_Mobile": "9845245145",
"Mother_Email": "mathi#gmail.com",
"Mother_Education": "B com",
"Mother_Occupation": "Self Employer",
"Mother_Name_Of_The_Organisation": "Self Employer",
"Mother_Designation": "Self Employer",
"Mother_Annual_Income": "200000",
"Mother_Office_Or_Business_Address": null,
"Sibling_Details": null,
"Land_Line_Number": "044-2121444",
"Guardian_Name": null,
"Guardian_Mobile": null,
"Guardian_Email": null,
"Relationship": null,
"Guardian_Education": null,
"Guardian_Occupation": null,
"Guardian_Name_Of_The_Organisation": null,
"Guardian_Designation": null,
"Guardian_Annual_Income": null,
"Guardian_Office_Or_Business_Address": null,
"Guardian_Land_Line_Number": null,
"LeaveLetterApplied": null,
"Message": null,
"Date": null,
"Notify": null,
"Status": null
}
]
}
how to fetch data from this jsonresponse and fill the particular section.Hoping for the help.Thanks in advance.
Consider you have static 3 sections:
1) Its a good habit to declare constants.
let SEC_STUDENT = 0
let SEC_FATHER = 1
let SEC_MOTHER = 2
2) Get array from response
enum Student_Key : String
{
case ID = "Student_ID"
case FirstName = "FirstName"
case LastName = "LastName"
//Define all keys so on
}
enum Father_Key : String
{
case Name = "Father_Name"
case Mobile = "Father_Mobile"
//Define all keys so on
}
enum Mother_Key : String
{
case Name = "Mother_Name"
case Mobile = "Mother_Mobile"
//Define all keys so on
}
//Define global
var arrStudent : Array<[String:String]> = []
var arrMother : Array<[String:String]> = []
var arrFather : Array<[String:String]> = []
//Add new method to parse response
func parseData(response : [String:Any]) {
let arrayData = response["Student_Details"] as! [Any]
//You can load only one record in your current way.
let studentData = arrayData[0] as! [String:Any]
arrStudent.append(["key":Student_Key.ID.rawValue ,
"value" : String(describing: studentData[Student_Key.ID.rawValue])])
arrStudent.append(["key":Student_Key.FirstName.rawValue,
"value": String(describing: studentData[Student_Key.FirstName.rawValue])])
arrStudent.append(["key":Student_Key.LastName.rawValue,
"value": String(describing: studentData[Student_Key.LastName.rawValue])])
//You have to add all keys mannualy
arrMother.append(["key":Father_Key.Name.rawValue,
"value": String(describing: studentData[Father_Key.Name.rawValue])])
arrMother.append(["key":Father_Key.Mobile.rawValue,
"value": String(describing: studentData[Father_Key.Mobile.rawValue])])
arrFather.append(["key":Mother_Key.Name.rawValue,
"value": String(describing: studentData[Mother_Key.Name.rawValue])])
arrFather.append(["key":Mother_Key.Mobile.rawValue,
"value": String(describing: studentData[Mother_Key.Mobile.rawValue])])
yourTable.reloadData()
}
3) Return section, which you already implemented.
4) Return number of rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if indexPath.section == SEC_STUDENT
{
return arrStudent.count
}
else if indexPath.Section == SEC_FATHER
{
return arrFather.count
}
else if indexPath.Section == SEC_MOTHER
{
return arrMother.count
}
else {
return 0
}
}
5) Load cell for index
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier") as! YourCell
let dictData : [String:Any]
if indexPath.section == SEC_STUDENT
{
dictData = arrStudent[indexPath.row] as! [String:Any]
}
else if indexPath.Section == SEC_FATHER
{
dictData = arrFather[indexPath.row] as! [String:Any]
}
else if indexPath.Section == SEC_MOTHER
{
dictData = arrayData[indexPath.row] as! [String:Any]
}
cell.lblKey = data["key"]
cell.lblValue = data["value"]
return cell
}
** Notes
1) It may be your requirement but this is not a correct way to handle and show json.
2) Currently you can only show on student record then it should be detail page of student.
3) I just typed code to show way to achieve your goal. You have to handle things in your code.

Parse JSON from GoogleApiBooks

I'm trying to parse this JSON but it don't works.
This is the JSON:
{
"kind": "books#volumes",
"totalItems": 1,
"items": [
{
"kind": "books#volume",
"id": "uCHmPQAACAAJ",
"etag": "aBZ3KnoRsq4",
"selfLink": "https://www.googleapis.com/books/v1/volumes/uCHmPQAACAAJ",
"volumeInfo": {
"title": "Psicologia delle folle",
"authors": [
"Gustave Le Bon"
],
"publishedDate": "2004",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "8850206240"
},
{
"type": "ISBN_13",
"identifier": "9788850206247"
}
],
"readingModes": {
"text": false,
"image": false
},
"pageCount": 251,
"printType": "BOOK",
"categories": [
"Psychology"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "preview-1.0.0",
"language": "it",
},
"saleInfo": {
"country": "IT",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "IT",
"viewability": "NO_PAGES",
"embeddable": false,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": false
},
"pdf": {
"isAvailable": false
},
,
"accessViewStatus": "NONE",
"quoteSharingAllowed": false
}
}
]
}
And this is the code that i'm using:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var url = "https://www.googleapis.com/books/v1/volumes?q=isbn9788850206247&key=my-key"
Alamofire.request(url).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["items"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
print(self.arrRes)
}
if self.arrRes.count > 0 {
self.tableProva.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableProva.dequeueReusableCell(withIdentifier: "cellProva", for: indexPath) as! CellProvaClass
var dict = arrRes[indexPath.row]
cell.titleLabel?.text = dict["title"] as? String
cell.authorLabel?.text = dict["authors"] as? String
return cell
}
How can I solve this problem?
This is your JSON Reponse ( in short format) :
And this is the data structure (Array and dictionary format) :
Now you have to access : title and authors so here is your value in cellforRowAtIndexPath Method , a dictionary having name dict stores values of volumeInfo ( a Dictionary) :
so you have to use this way to access title :
cell.titleLabel?.text = dict["volumeInfo"]["title"] as? String
//To Fetch Author array
if let authorArray = dict["volumeInfo"]["authors"] as? NSArray{
print(authorArray)
}
and then to access author is an array so which index of value you want to show in cell.authorLabel .
In Second Screenshot those which are enclosed with {} is Dictionary and [] is Array
First try to show Title and then same way try to fetch value of author array and set according to your requirement.
Feel Free to comment if any further issue.
When you are parsing the JSON on line
if let resData = swiftyJsonVar["items"].arrayObject {
you will receive an object of NSDictionary which contains all other nested elements & arrays in keys. In your tableView delegate you are directly accessing the value from arrRes by unboxing it to NSDictionary object. All the entries are available in an array named items which further has a nested object volumeInfo which contains the info about title & another array of Authors.
You need to extract the further nested objects from arrRes object to use it in your tableView cellForRowAtIndex delegate function.
Let me know if you need any further help.

Alamofire json swift 2.2

I'm trying to take out some data of facebook place's names with Alamofire but i have no luck.
This is what i've tried and i cant figure out how to make it work.
xcode 7.3
swift2.2
So the result of the graph api is this
{
"data": [
{
"category": "Local business",
"category_list": [
{
"id": "272705352802676",
"name": "Outdoors"
},
{
"id": "115725465228008",
"name": "Region"
}
],
"location": {
"street": "Athens",
"city": "Palai\u00f3n F\u00e1liron",
"state": "",
"country": "Greece",
"zip": "17562",
"latitude": 37.9284637008,
"longitude": 23.6944070162
},
"name": "THE NAME OF THE PLACE",
"id": "THE ID"
}
and i want to go inside "data" and take only the name and the ID of the place which are the 2 last lines.
And this is my code!
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "https://graph.facebook.com/search", parameters: ["q": "", "type": "place", "center": "37.928319,23.7036673", "distance": "10000", "access_token": "ACCESS-TOKEN", "expires_in": "5184000"])
.responseJSON { response in
if let JSON = response.result.value {
print("JSON: \(JSON["data"]!["name"]!)")
}
}
}
and i get this error
fatal error: unexpectedly found nil while unwrapping an Optional value
Any idea why?
Ok this was easy i guess and it didn't worth the question but this is the solution
Alamofire.request(.GET, "https://graph.facebook.com/search", parameters: ["q": "", "type": "place", "center": "37.928319,23.7036673", "distance": "10000", "access_token": "475827182628380|6U-mk-1etGQHwrXRSMF4Ht2zOyc", "expires_in": "5184000"])
.responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["data"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
if self.arrRes.count > 0 {
self.kati.reloadData()
}
}
}
And at the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("checkInCell", forIndexPath: indexPath)
var dict = arrRes[indexPath.row]
cell.textLabel?.text = dict["name"] as? String
//cell.detailTextLabel?.text = dict["email"] as? String
return cell
}
Just dont forget to use SwiftyJSON too!