Decode JSON Swift 4 - ios

Can someone tell what is wrong with the code? I'm trying to parse the JSON from the server into variables to store the values. When i'm running the code, i'm not getting any errors. When i'm doing the print(users) after decoding the data, it's not returning anything. Can someone help me with this issue?
This is the code i'm using to retrieve the data from the server.
guard let url = URL(string: "my-url") else { return }
let session = URLSession.shared
let task = session.dataTask(with: url) { (data, _, _) in
guard let data = data else { return }
do {
let user = try JSONDecoder().decode(User.self, from: data)
print(user)
} catch {}
}
task.resume()
JSON result from the server
{
"UserId": "55844ef7-3f05-4560-8b37-216df422ffb8",
"ContactsDto": [
{
"Id": null,
"UserId": null,
"FriendUserId": "e61d09f8-9aec-4035-b0be-c36abea2d82b",
"FirstName": null,
"LastName": null,
"Email": "",
"PhonePrefix": null,
"Phone": "54943597",
"InviteStatus": "pending",
"UserStatus": null,
"ErrorCode": 0,
"ErrorMessage": null
},
{
"Id": null,
"UserId": null,
"FriendUserId": "b2e0d6d7-d97c-475e-a2ab-71cb8091a7a0",
"FirstName": null,
"LastName": null,
"Email": "",
"PhonePrefix": null,
"Phone": "207-7575",
"InviteStatus": "pending",
"UserStatus": null,
"ErrorCode": 0,
"ErrorMessage": null
},
{
"Id": null,
"UserId": null,
"FriendUserId": "8f8d6061-3a69-4641-ac40-329a824ff4e1",
"FirstName": null,
"LastName": null,
"Email": "",
"PhonePrefix": null,
"Phone": "58511968",
"InviteStatus": "pending",
"UserStatus": null,
"ErrorCode": 0,
"ErrorMessage": null
},
{
"Id": null,
"UserId": null,
"FriendUserId": "40c1e461-eb98-4e18-9363-13cfa460fe7e",
"FirstName": null,
"LastName": null,
"Email": "",
"PhonePrefix": null,
"Phone": "57864550",
"InviteStatus": "accepted",
"UserStatus": null,
"ErrorCode": 0,
"ErrorMessage": null
}
],
"ErrorCode": 0,
"ErrorMessage": null
}
My Structure
struct User: Decodable {
let UserId: String?
let ContactsDto: [ContactsDto]?
let ErrorCode: Int?
let ErrorMessage: String?
}
struct ContactsDto : Decodable {
let Id : String?
let UserId : String?
let FriendUserId : String?
let FirstName : String?
let LastName : String?
let Email : String?
let PhonePrefix : String?
let Phone : String?
let InviteStatus : String?
let UserStatus : String?
let ErrorCode : String?
let ErrorMessage : String?
}

Based on your errors and as Josh told you in the comments, the types on your model are not correct.
For example, one of your ContactDto object is this:
{
"Id": null,
"UserId": null,
"FriendUserId": "e61d09f8-9aec-4035-b0be-c36abea2d82b",
"FirstName": null,
"LastName": null,
"Email": "",
"PhonePrefix": null,
"Phone": "54943597",
"InviteStatus": "pending",
"UserStatus": null,
"ErrorCode": 0,
"ErrorMessage": null
},
The ErrorCode type is a number (it looks like an integer), but in your model struct is a String?.
Please check every field to get all types, then fix the model and try again.

From looking at your code, the way you are trying to decode the JSON isn't correct.
You aren't returning an array of User, but a single User Object.
As such you could try the following:
let user = try! JSONDecoder().decode(User.self, from: data)

Related

Parse valid objects from JSON array in Swift

I have a codable struct like this
struct User: Codable {
let id: String
let registrationId: String
let firstName: String?
let lastName: String?
}
Now, the response from the server contains an array like this
[
{
"id": "1",
"registrationId": "r1",
"firstName": "Jon",
"lastName": "Doe"
},
{
"id": "2",
"registrationId": null,
"firstName": null,
"lastName": null
},
{
"id": "3",
"registrationId": null,
"firstName": null,
"lastName": null
},
{
"id": "4",
"registrationId": "r4",
"firstName": "Jon",
"lastName": "Snow"
}
]
I want to parse this as [User] but only those who have a valid(not null) registrationId. I know how to parse JSON in swift. But the problem here is because of the two invalid data in the middle the whole response will run into decoding error. But I want to parse it as an array of [User] containing valid ones(in this case first and last object).
Any hints or help is much appreciated.
1- Make registrationId an optional
let registrationId: String?
2-
let res = try JSONDecoder().decode([User].self,from:data)
let filtered = res.filter { $0.registrationId != nil }
after all, this data must come from a database or an array. By making the id parameter as the primary key, the registrationId parameter as a foreign key, and if you are working on the registrationId parameter, you can make a productive sequence or if it is on the array, you can link the method that generates the sequence for that registrationId.
Now I know how to achieve this.
struct User: Codable {
let id: String
let registrationId: String
let firstName: String?
let lastName: String?
}
struct WrappedDecodableArray<Element: Decodable>: Decodable {
let elements: [Element]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var elements = [Element]()
while !container.isAtEnd {
if let element = try? container.decode(Element.self) {
elements.append(element)
} else {
// move the container currentIndex forward
_ = try container.decode(Block.self)
}
}
self.elements = elements
}
private struct Block: Decodable {}
}
func testUserParsing() {
let jsonStr = """
[
{
"id": "1",
"registrationId": "r1",
"firstName": "Jon",
"lastName": "Doe"
},
{
"id": "2",
"registrationId": null,
"firstName": null,
"lastName": null
},
{
"id": "3",
"registrationId": null,
"firstName": null,
"lastName": null
},
{
"id": "4",
"registrationId": "r4",
"firstName": "Jon",
"lastName": "Snow"
}
]
"""
let jsonData = jsonStr.data(using: .utf8)!
let wrappedArray = try! JSONDecoder().decode(WrappedDecodableArray<User>.self, from: jsonData)
print(wrappedArray.elements)
}
It would have been more elegant if we could override the init(from decoder: Decoder) for Array under certain conditions like extension Array where Element == User. But looks like this is not possible. Initializer inside the extension can not override the original one and hence never get called.
So for now looks like wrapping with a struct is the only solution.

how to set json data in table view [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I want to get data from Json and put it in the table and display it from the API via Alamofire through the 'Post' process that has parameters containing the page number
I want get "results" ..
{
"responseCode": 200,
"message": null,
"status": true,
"results": [
{
"id": 971,
"title": "ST201972362",
"cdate": "07/31/2019",
"summary": "test",
"address": "",
"timer": "77876203",
"lat": "31.515934",
"lng": "34.4494066",
"source": "2",
"CreatedOn": "2019-07-31T13:38:46.927",
"done_940": null
},
{
"id": 970,
"title": "ST201972356",
"cdate": "07/30/2019",
"summary": "ov",
"address": "",
"timer": "0",
"lat": "31.5159315",
"lng": "34.4493925",
"source": "2",
"CreatedOn": "2019-07-30T15:26:00.077",
"done_940": null
},
{
"id": 964,
"title": "ST201972341",
"cdate": "07/29/2019",
"summary": "تجربة بلاغ ",
"address": "",
"timer": "0",
"lat": "21.5066086",
"lng": "39.1758587",
"source": "2",
"CreatedOn": "2019-07-29T19:06:58.817",
"done_940": null
},
{
"id": 959,
"title": "ST201972820252314",
"cdate": "07/28/2019",
"summary": "اااااا",
"address": "",
"timer": "0",
"lat": "21.5066716",
"lng": "39.1758483",
"source": "1",
"CreatedOn": "2019-07-28T11:45:02.493",
"done_940": null
},
{
"id": 957,
"title": "ST201972312",
"cdate": "07/28/2019",
"summary": "تمتمتم",
"address": "",
"timer": "0",
"lat": "31.5397884",
"lng": "34.4544891",
"source": "2",
"CreatedOn": "2019-07-28T08:56:43.577",
"done_940": null
},
{
"id": 956,
"title": "ST201972312",
"cdate": "07/28/2019",
"summary": "لا تنام",
"address": "",
"timer": "0",
"lat": "31.5397238",
"lng": "34.4540829",
"source": "2",
"CreatedOn": "2019-07-28T08:56:00.15",
"done_940": null
},
{
"id": 955,
"title": "ST201972311",
"cdate": "07/28/2019",
"summary": "تجربه جديد",
"address": "",
"timer": "0",
"lat": "31.5395001",
"lng": "34.4542211",
"source": "2",
"CreatedOn": "2019-07-28T08:52:09.81",
"done_940": null
},
{
"id": 953,
"title": "ST201972309",
"cdate": "07/28/2019",
"summary": "يلا",
"address": "",
"timer": "0",
"lat": "31.5110196",
"lng": "34.4784933",
"source": "2",
"CreatedOn": "2019-07-28T05:30:29.647",
"done_940": null
},
{
"id": 952,
"title": "ST201972309",
"cdate": "07/28/2019",
"summary": "ماك ١",
"address": "",
"timer": "0",
"lat": "31.5110291",
"lng": "34.4785841",
"source": "2",
"CreatedOn": "2019-07-28T05:29:09.943",
"done_940": null
},
{
"id": 949,
"title": "ST201972307",
"cdate": "07/28/2019",
"summary": "مرحبا",
"address": "",
"timer": "0",
"lat": "31.5443154",
"lng": "34.4585304",
"source": "2",
"CreatedOn": "2019-07-28T00:20:42.753",
"done_940": null
}
],
"done_940": "2/811"
}
You can follow some steps:
Step 1: need to create model
struct ResultObject {
var responseCode: Int?
var message: String?
var status: Bool?
var result: [Result]
public init(response: [String: Any]) {
self.responseCode = response["responseCode"] as? Int
self.message = response["message"] as? String
self.status = response["status"] as? Bool
let results = response["result"] as! [[String: Any]]
self.result = []
for item in results {
let result = Result(result: item)
self.result.append(result)
}
}
struct Result {
var id: String?
var title: String?
var cdate: String?
var summary: String?
var address: String?
var timer: String?
var lat: String?
var lng: String?
var source: String?
var CreatedOn: String?
var done_940: String?
public init(result: [String: Any]) {
self.id = result["id"] as? String
self.title = result["title"] as? String
self.cdate = result["cdate"] as? String
self.summary = result["summary"] as? String
self.address = result["address"] as? String
self.timer = result["timer"] as? String
self.lat = result["lat"] as? String
self.lng = result["lng"] as? String
self.source = result["source"] as? String
self.CreatedOn = result["CreatedOn"] as? String
self.done_940 = result["done_940"] as? String
}
}
}
Step 2: You check response from Alamofile
if you get json then
let test = ResultObject(response: responseJson)
print(test)
incase you get response is type Response you must convert into json
let responseJSON = try? JSONSerialization.jsonObject(with: response.data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
let test = ResultObject(response: responseJSON)
print(test)
}
Let me know when you have some other problems.

How to retrieve data from json response

I am trying to get data from json response, and the response format is mentioning below. I want to fetch "recipient" dictionary, and need to show in table.each cell contains name and unique id and image. How to get this dictionary to story in local dictionary?
{
"success": 1,
"status": 200,
"data": {
"chat": [
{
"id": 5,
"status": 0,
"created_at": "2019-02-19 13:29:15",
"updated_at": "2019-02-19 13:29:15",
"recipient": {
"id": 5,
"unique_id": "10004",
"name": "Pandu",
"avatar": "https://www.planetzoom.co.in/img/default_avatar_female.png"
},
"conversation": {
"id": 67,
"chat_id": 5,
"user_id": 4,
"type": 0,
"message": "I have sent a msg now",
"status": 0,
"created_at": "2019-02-26 04:02:20"
}
},
{
"id": 3,
"status": 0,
"created_at": "2019-02-19 13:17:49",
"updated_at": "2019-02-19 13:17:49",
"recipient": {
"id": 8,
"unique_id": "10007",
"name": "Mahitha",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/cZt9yQlBzIEewOdQ1lYZhl3dFiOv2k3bxG7HLOzR.jpeg"
},
"conversation": {
"id": 57,
"chat_id": 3,
"user_id": 4,
"type": 0,
"message": "Hi",
"status": 0,
"created_at": "2019-02-24 13:04:29"
}
},
{
"id": 2,
"status": 0,
"created_at": "2019-02-19 07:59:05",
"updated_at": "2019-02-19 07:59:05",
"recipient": {
"id": 1,
"unique_id": "1111",
"name": "Angadi World Tech",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/NlVzdUAfmLfIG9677szYZz7NkWyY4ULHAqnlCiiV.png"
},
"conversation": {
"id": 21,
"chat_id": 2,
"user_id": 4,
"type": 0,
"message": "Hi\\uD83D\\uDE0A",
"status": 0,
"created_at": "2019-02-21 10:35:26"
}
}
]
}
}
The best way to decode json in my opinion is to use Codable
I've created a few structs to represent the data and to decode it, please note this json wasn't valid so have had to wrap it in {}
Here's the json:
let jsonString = """
{
"chat": [
{
"id": 12,
"status": 0,
"created_at": "2019-02-22 04:57:12",
"updated_at": "2019-02-22 04:57:12",
"recipient": {
"id": 26,
"unique_id": "10024",
"name": "Kaverinew",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/1PyI4ceM3zPsG1fxbfatktWUT75sOE2Ttah8ctIp.png"
},
"conversation": {
"id": 65,
"chat_id": 12,
"user_id": 4,
"type": 1,
"message": "https://www.planetzoom.co.in/storage/chat/message/e759KWdSBegwXslAoS2xst0lohbbjNZMdpVnbxQG.png",
"status": 0,
"created_at": "2019-02-25 15:39:24"
}
},
{
"id": 6,
"status": 0,
"created_at": "2019-02-20 07:16:35",
"updated_at": "2019-02-20 07:16:35",
"recipient": {
"id": 7,
"unique_id": "10006",
"name": "Hema",
"avatar": "https://www.planetzoom.co.in/img/default_avatar_female.png"
},
"conversation": {
"id": 44,
"chat_id": 6,
"user_id": 4,
"type": 1,
"message": "https://www.planetzoom.co.in/storage/chat/message/qJjOtCRcBKBuq3UKaKVuVOEIQhaVPeJr3Bd4NoLo.png",
"status": 0,
"created_at": "2019-02-22 10:17:49"
}
}
]
}
Here are the structs:
struct Recipient: Codable {
var identifier: Int
var unique_id: Int
var name: String
var avatar: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case unique_id = "unique_id"
case name = "name"
case avatar = "avatar"
}
}
struct Conversation: Codable {
var identifier: Int
var chat_id: Int
var user_id: Int
var conversationType: Int
var message: String
var status: Int
var created_at: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case chat_id = "chat_id"
case user_id = "user_id"
case conversationType = "type"
case message = "message"
case status = "status"
case created_at = "created_at"
}
}
struct Chat: Codable {
var identifier: Int
var status: Int
var created_at: String
var updated_at: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case status = "status"
case created_at = "created_at"
case updated_at = "updated_at"
}
}
struct RootObject: Codable {
var chats: [Chat]
enum CodingKeys: String, CodingKey {
case chats = "chat"
}
}
And here is how you decode it:
if let jsonData = jsonString.data(using: .utf8) {
do {
let root = try JSONDecoder().decode(RootObject.self, from: jsonData)
} catch {
print(error)
}
}
Assuming you already have a Data object representing your JSON you can use JSONSerialization to convert it to concrete Swift object. Once that is done you simply need to go step by step and extract the data. Something like the following should work nicely:
func retrieveRecipients(jsonData: Data?) throws -> [[String: Any]] {
guard let data = jsonData else { throw NSError(domain: "Parsing Recipients", code: 404, userInfo: ["dev_message": "Null JSON data inserted"]) }
guard let parsedJSON = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) else { throw NSError(domain: "Parsing Recipients", code: 500, userInfo: ["dev_message": "Data could not be parsed as JSON"]) }
guard let object = parsedJSON as? [String: Any] else { throw NSError(domain: "Parsing Recipients", code: 500, userInfo: ["dev_message": "Parsed JSON is not a dictionary"]) }
guard let items = object["chat"] as? [[String: Any]] else { throw NSError(domain: "Parsing Recipients", code: 404, userInfo: ["dev_message": "JSON is missing \"chat\" array"]) }
return items.compactMap { $0["recipient"] as? [String: Any] }
}
This is all the safety enabled. Otherwise you could do it very shortly:
func retreiveRecipientsStrict(jsonData: Data?) -> [[String: Any]] {
return ((try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any])["chat"] as! [[String: Any]]).compactMap { $0["recipient"] as? [String: Any] }
}
But this will crash if there is a mistake and it will be extremely hard to debug what went wrong.

How to use Decodable with Generics & Core data in Swift

Below is my JSON. I need to decode the entries in it using "Decodable" CoreData model class. The Entries(and corresponding model classes in Core data) are different as you can see against key "c". So this variable "c" needs to be of type generic i guess. So it can accept all 6(fixed!) types of models viz. "consultation_time", "child", "appointment", "child_doctor", "clinic", "clinic_user". Not sure how to implement this .
Model classes generated by core data.(Have used https://forums.developer.apple.com/thread/96860#295158 this link to implement Decodable with Coredata.)
Updates+CoreDataClass.swift
import Foundation
import CoreData
public class Updates: NSManagedObject {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name ?? "" , forKey: .name)
try container.encode(ids , forKey: .ids)
try container.encode(c , forKey: .c)
try container.encode(u , forKey: .u)
try container.encode(d , forKey: .d)
}
public required convenience init(from decoder: Decoder) throws {
guard let contextUserInfoKey = CodingUserInfoKey.context,
let managedObjectContext = decoder.userInfo[contextUserInfoKey] as? NSManagedObjectContext,
let entity = NSEntityDescription.entity(forEntityName:"Sync", in: managedObjectContext) else { fatalError() }
self.init(entity: entity, insertInto: managedObjectContext)
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
ids = try values.decode(Array?.self, forKey: .ids)
c = try values.decode(Array.self, forKey: .c)
u = try values.decode(Array.self, forKey: .u)
d = try values.decode(Array.self, forKey: .d)
}
}
Updates+CoreDataProperties.swift
import Foundation
import CoreData
extension Updates : Codable {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Updates>
{
return NSFetchRequest<Updates>(entityName: "Updates")
}
#NSManaged public var name: String?
#NSManaged public var ids: [String]?
#NSManaged public var c: [Parent]?
#NSManaged public var u: [Parent]?
#NSManaged public var d: [Parent]?
//** Here Parent is another Coredata entity model class. And sub entities are created from it. So at runtime c, u & d can have any of values amongst the sub-entities(Child, Clinic, Appointment etc.). So what happens is while decoding c, u and d it tries to decode "Parent" and not the subentities , becoz it doesnt know exact type of subentity(Child, Clinic, Appointment etc.). It just knows it as "Parent".
enum CodingKeys: String, CodingKey {
case name
case ids = "sync_token"
case c
case u
case d
}
}
JSON :
"updates": [
{
"name": "consultation_time",
"ids": [ "id" ],
"c": [
{
"id": 1,
"_id": 1001,
"is_active_morning": true,
"morning_start_time": "2016-07-01T09:30:00.000+05:30",
"morning_end_time": "2016-07-01T12:30:00.000+05:30",
"is_active_evening": true,
"evening_start_time": "2016-07-01T18:00:00.000+05:30",
"evening_end_time": "2016-07-01T19:00:00.000+05:30",
"day": "Monday",
"doctor_id": 2,
"clinic_id": 1
}
],
"u": [],
"d": []
},
{
"name": "child",
"ids": [ "id" ],
"c": [
{
"id": 1,
"_id": 1022,
"name": "Sarvesh",
"gender": "male",
"dob": "2017-01-01T17:48:20.393+05:30",
"profile_image": "https://tpn-production.s3.amazonaws.com/710e34ae-49bb-11e7-99dc- 0a6eb743b653.jpg",
"is_member": true,
"email": "kiran#joshsoftware.com",
"birthday_wish_sms": true,
"program_launch_sms": true,
"vaccine_reminder_same_day_sms": true,
"vaccine_reminder_two_days_prior_sms": true,
"vaccine_reminder_week_prior_sms": true,
"parent_name": "Kiran"
}
],
"u": [],
"d": []
},
{
"name": "appointment",
"ids": [ "id" ],
"c": [
{
"id": 1,
"_id": 1076,
"start_time": "2016-07-01T19:10:00.000+05:30",
"end_time": "2016-07-01T19:15:00.000+05:30",
"schedule": "Evening",
"status": "open",
"weight": 9.2,
"height": 45,
"head_circumference": null,
"temperature": null,
"heart_rate": null,
"blood_pressure": null,
"respiratory_rate": null,
"bill_amount": null,
"child_id": 1,
"doctor_id": 2,
"clinic_id": 1,
"amount_received_for_consultation": null,
"amount_received_for_indoor_admission": null,
"amount_received_for_nebulization": null,
"amount_received_for_injection": null,
"amount_received_for_vaccination": null,
"payment_mode": null,
"total_amount_received": null,
"pending_amount_till_date": 100
}
],
"u": [],
"d": []
},
{
"name": "child_doctor",
"ids": [ "id" ],
"c": [
{
"id": 129089,
"_id": null,
"child_id": 12617,
"doctor_id": 2,
"clinic_id": 1
}
],
"u": [],
"d": []
},
{
"name": "clinic",
"ids": [ "id" ],
"c": [
{
"id": 1,
"_id": 2701,
"name": "Wellness Clinic",
"landline": "02027654321",
"address": {
"address": "A13/14/15, Sunflower Apartments",
"area": "Baner",
"postal_code": "411045",
"city": "Pune",
"state": "MH",
"country": "IN",
"lat": "18.561338",
"lng": "73.785545"
},
"mobile": null,
"email": null
}
],
"u": [],
"d": []
},
{
"name": "clinics_user",
"ids": [
"id"
],
"c": [
{
"id": 1,
"clinic_id": 1,
"is_active": true,
"appointment_time_slot": 5,
"consultation_rate": 400,
"block_online_appointments_morning": false,
"block_online_appointments_evening": false,
"show_generic_name_first": false,
"show_scheduled_vaccine": true,
"show_regional_translation_of_number": false,
"doctor_id": 2
}
],
"u": [],
"d": []
}
]

how to parse a JSON with Array of Dictionaries iOS swift

I am having a JSON array which looks like this:
func fetchProfessionalData() {
guard let url = URL(string:"urlString") else { return }
let parameters = ["Address":""] as [String : Any]
Alamofire.request(url, method: .post, parameters:parameters,encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
let jsonData = response.result.value as! NSArray
print("response:\(jsonData)")
}
self.listTableView.reloadData()
break
case .failure(let error):
print(error)
}
}
}
this is the output I'm getting when I print it:
response: [
{
"userId": 2,
"userName": "jhonsmith",
"password": "1234",
"userTypeId": 3,
"firstName": "jhon",
"lastName": "smith",
"dob": "0004-03-04T00:00:00",
"phoneNumber": "40556677",
"mobile": "324",
"email": "jhon",
"profilePic": "avatar3.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "2 years",
"about": "I am expertised in beauty care",
"addressId": 2,
"addressLine1": "7 Freymuth Rd",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 3,
"serviceName": "BeautyCare",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 5,
"subServiceName": "HairCare",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 500,
"serviceProviderId": 2,
"providerServiceId": 1
},
{
"serviceId": 4,
"serviceName": "Carpentry",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 6,
"subServiceName": "All Carpentry",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 400,
"serviceProviderId": 2,
"providerServiceId": 1002
}
],
"rating": 3,
"price": 0,
"searchLocationId": 0
},
{
"userId": 4,
"userName": "User",
"password": "new",
"userTypeId": 3,
"firstName": "Emma",
"lastName": "Williams",
"dob": "1998-06-23T00:00:00",
"phoneNumber": "7787787887",
"mobile": "9879789990",
"email": "user#testmail.com",
"profilePic": "avatar4.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "2 years",
"about": "Test",
"addressId": 4,
"addressLine1": "Big river dr",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 1,
"serviceName": "Cleaning",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 1,
"subServiceName": "Dusting",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 2,
"serviceProviderId": 4,
"providerServiceId": 3
}
],
"rating": 0,
"price": 0,
"searchLocationId": 0
},
{
"userId": 5,
"userName": "RobertThomas",
"password": "rb",
"userTypeId": 3,
"firstName": "Robert",
"lastName": "Thomas",
"dob": "1999-01-04T00:00:00",
"phoneNumber": "889955643",
"mobile": "1234567890",
"email": "rb1234#testmail.com",
"profilePic": "th.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "1 Year",
"about": "Robert Thomas",
"addressId": 5,
"addressLine1": "Little Piney Dr",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 2,
"serviceName": "ChildCare",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 3,
"subServiceName": "Baby Sitting",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 7,
"serviceProviderId": 5,
"providerServiceId": 4
}
],
"rating": 0,
"price": 0,
"searchLocationId": 0
}
]
Now I am having a tableViewCell where I have to show "userName", "profilePic","rating","email" and "serviceName" under "lstServiceProviders".So far I am able to show name,image,email,rating but "lstServiceProviders" is another array of dictionaries. I want to show all the services provided by that serviceProvider in cell.
lets say in json 1st dict the "userName":"jhonsmith" is having "lstServicePrpviders" with an array of two dictionaries with "serviceName": "BeautyCare" in 1st Dict and "serviceName":"Carpentry" in 2nd Dict. I want to show both BeautyCare and Carpentry in one cell. how to do this.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let listCell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath) as! ListTableViewCell
let string = "imageBaseUrl\(models![indexPath.row].profilePic!)"
let escapedAddress = string.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlQueryAllowed)
listCell.listCellImage.image = UIImage(url: URL(string: escapedAddress!))
listCell.listCellNamesLabel.text = models![indexPath.row].userName!
let rating = models![indexPath.row].rating!
listCell.listCellRating.text = "(\(rating)/5 & 5 Comments)"
listCell.listCellStarRating.text = ratingArray[indexPath.row]
for i in 0..< models![indexPath.row].lstServiceProviders!.count {
listCell.listCellServicesLbl.text =
models![indexPath.row].lstServiceProviders[i].serviceName
}
return listCell
}
[Swift 4] You can use models with Codable to easily manage your tableviewcell.
See the Code below and run in a playground, you will understand that i have created model objects which is easy to loop and manage:
var json = """
[
{
"userId": 2,
"userName": "jhonsmith",
"password": "1234",
"userTypeId": 3,
"firstName": "jhon",
"lastName": "smith",
"dob": "0004-03-04T00:00:00",
"phoneNumber": "40556677",
"mobile": "324",
"email": "jhon",
"profilePic": "avatar3.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "2 years",
"about": "I am expertised in beauty care",
"addressId": 2,
"addressLine1": "7 Freymuth Rd",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 3,
"serviceName": "BeautyCare",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 5,
"subServiceName": "HairCare",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 500,
"serviceProviderId": 2,
"providerServiceId": 1
},
{
"serviceId": 4,
"serviceName": "Carpentry",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 6,
"subServiceName": "All Carpentry",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 400,
"serviceProviderId": 2,
"providerServiceId": 1002
}
],
"rating": 3,
"price": 0,
"searchLocationId": 0
},
{
"userId": 4,
"userName": "User",
"password": "new",
"userTypeId": 3,
"firstName": "Emma",
"lastName": "Williams",
"dob": "1998-06-23T00:00:00",
"phoneNumber": "7787787887",
"mobile": "9879789990",
"email": "user#testmail.com",
"profilePic": "avatar4.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "2 years",
"about": "Test",
"addressId": 4,
"addressLine1": "Big river dr",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 1,
"serviceName": "Cleaning",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 1,
"subServiceName": "Dusting",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 2,
"serviceProviderId": 4,
"providerServiceId": 3
}
],
"rating": 0,
"price": 0,
"searchLocationId": 0
},
{
"userId": 5,
"userName": "RobertThomas",
"password": "rb",
"userTypeId": 3,
"firstName": "Robert",
"lastName": "Thomas",
"dob": "1999-01-04T00:00:00",
"phoneNumber": "889955643",
"mobile": "1234567890",
"email": "rb1234#testmail.com",
"profilePic": "th.jpg",
"profileImage": null,
"isDeleted": false,
"company": "",
"experience": "1 Year",
"about": "Robert Thomas",
"addressId": 5,
"addressLine1": "Little Piney Dr",
"addressLine2": "",
"city": "St.Louis",
"state": "MO",
"country": "USA",
"zipCode": "63367",
"serviceProviderId": 0,
"serviceId": 0,
"subServiceId": 0,
"relevantExp": null,
"costPerHour": 0,
"spbRow": null,
"lstServiceProviders": [
{
"serviceId": 2,
"serviceName": "ChildCare",
"serviceDescription": null,
"serviceLogo": null,
"serviceIsDeleted": false,
"serviceIdFK": 0,
"subServiceId": 3,
"subServiceName": "Baby Sitting",
"subServiceDescription": null,
"subServiceLogo": null,
"subServiceIsDeleted": false,
"costPerHour": 7,
"serviceProviderId": 5,
"providerServiceId": 4
}
],
"rating": 0,
"price": 0,
"searchLocationId": 0
}
]
""".data(using: .utf8)
struct LstServiceProviders : Codable {
let serviceId : Int?
let serviceName : String?
let serviceDescription : String?
let serviceLogo : String?
let serviceIsDeleted : Bool?
let serviceIdFK : Int?
let subServiceId : Int?
let subServiceName : String?
let subServiceDescription : String?
let subServiceLogo : String?
let subServiceIsDeleted : Bool?
let costPerHour : Int?
let serviceProviderId : Int?
let providerServiceId : Int?
enum CodingKeys: String, CodingKey {
case serviceId = "serviceId"
case serviceName = "serviceName"
case serviceDescription = "serviceDescription"
case serviceLogo = "serviceLogo"
case serviceIsDeleted = "serviceIsDeleted"
case serviceIdFK = "serviceIdFK"
case subServiceId = "subServiceId"
case subServiceName = "subServiceName"
case subServiceDescription = "subServiceDescription"
case subServiceLogo = "subServiceLogo"
case subServiceIsDeleted = "subServiceIsDeleted"
case costPerHour = "costPerHour"
case serviceProviderId = "serviceProviderId"
case providerServiceId = "providerServiceId"
}
}
struct RootModel : Codable {
let userId : Int?
let userName : String?
let password : String?
let userTypeId : Int?
let firstName : String?
let lastName : String?
let dob : String?
let phoneNumber : String?
let mobile : String?
let email : String?
let profilePic : String?
let profileImage : String?
let isDeleted : Bool?
let company : String?
let experience : String?
let about : String?
let addressId : Int?
let addressLine1 : String?
let addressLine2 : String?
let city : String?
let state : String?
let country : String?
let zipCode : String?
let serviceProviderId : Int?
let serviceId : Int?
let subServiceId : Int?
let relevantExp : String?
let costPerHour : Int?
let spbRow : String?
let lstServiceProviders : [LstServiceProviders]?
let rating : Int?
let price : Int?
let searchLocationId : Int?
enum CodingKeys: String, CodingKey {
case userId = "userId"
case userName = "userName"
case password = "password"
case userTypeId = "userTypeId"
case firstName = "firstName"
case lastName = "lastName"
case dob = "dob"
case phoneNumber = "phoneNumber"
case mobile = "mobile"
case email = "email"
case profilePic = "profilePic"
case profileImage = "profileImage"
case isDeleted = "isDeleted"
case company = "company"
case experience = "experience"
case about = "about"
case addressId = "addressId"
case addressLine1 = "addressLine1"
case addressLine2 = "addressLine2"
case city = "city"
case state = "state"
case country = "country"
case zipCode = "zipCode"
case serviceProviderId = "serviceProviderId"
case serviceId = "serviceId"
case subServiceId = "subServiceId"
case relevantExp = "relevantExp"
case costPerHour = "costPerHour"
case spbRow = "spbRow"
case lstServiceProviders = "lstServiceProviders"
case rating = "rating"
case price = "price"
case searchLocationId = "searchLocationId"
}
}
let Models = try! JSONDecoder().decode([RootModel].self, from: json!)
print(Models.count)
for item in Models {
print(item.lstServiceProviders?.count)
}
[Edit 1] If the response is Data, use the below:
URLSession.shared.dataTask(with: gitUrl) { (data, response
, error) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let models = try decoder.decode([RootModel].self, from: data)
} catch let err {
print("Err", err)
}
}.resume()
If the response is Json object like your output, use the below:
func fetchProfessionalData() {
guard let url = URL(string:"urlString") else { return }
let parameters = ["Address":""] as [String : Any]
Alamofire.request(url, method: .post, parameters:parameters,encoding: JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
// let jsonData = response.result.value as! NSArray
let jsonData = try JSONSerialization.data(withJSONObject: response.result, options: .prettyPrinted)
models = try JSONDecoder().decode([RootModel].self, from: jsonData)
print("response:\(jsonData)")
}
// self.listTableView.reloadData()
break
case .failure(let error):
print(error)
}
}
}
In your viewController, Declare varibale
var models: [RootModel]? {
didSet {
self.listTableView.reloadData()
}
}
In your tableview delegate method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return models.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Update your cell using models
// cell.text = models[indexPath.row].userName
}
[Edit 2] Add all string and then show the value.
var stringArray:[String] = []
for i in 0..< models![indexPath.row].lstServiceProviders!.count {
stringArray.append( models![indexPath.row].lstServiceProviders[i].serviceName)
}
listCell.listCellServicesLbl.text = stringArray.joined(separator: ", ")

Resources