Related
When clicked on each person , the subordinates list of that person should appear at the bottom. The whole list is dynamic .
{
"EmployeeId": "1",
"Name": "John",
"Position": "HR",
"Image": "",
"SubordinateCount": 6,
"Subordinates": [
{
"EmployeeId": "2",
"Name": "Sub john 1",
"Position": "Manager",
"Image": "",
"SubordinateCount": 1,
"Subordinates": [
{
"EmployeeId": "3",
"Name": "Joseph",
"Position": "Admin",
"Image": "",
"SubordinateCount": 1,
"Subordinates": [
{
"EmployeeId": "4",
"Name": "Raj",
"Position": "Software Developer",
"Image": "",
"SubordinateCount": 0,
"Subordinates": []
}
]
}
]
},
{
"EmployeeId": "5",
"Name": "Rahul",
"Position": "ERP Consultant",
"Image": "",
"SubordinateCount": 16,
"Subordinates": [
{
"EmployeeId": "6",
"Name": "Fam",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "7",
"Name": "Salman A Q",
"Position": "Software Developer",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "8",
"Name": "Mac",
"Position": "Software Developer",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "9",
"Name": "Mathew",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "10",
"Name": "Kim",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "11",
"Name": "Loren",
"Position": "Software Developer",
"Image": "",
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "12",
"Name": "Adam",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "13",
"Name": "Meera",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "14",
"Name": "MMM",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "15",
"Name": "Master",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "16",
"Name": "Michael",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "17",
"Name": "George",
"Position": "Consultant",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "18",
"Name": "Ahmedu A F",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "19",
"Name": "KKKK",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "20",
"Name": "xxx",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "21",
"Name": "DK",
"Position": "QA",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
}
]
},
{
"EmployeeId": "22",
"Name": "HHHH",
"Position": "Engineer",
"Image": "",
"SubordinateCount": 1,
"Subordinates": [
{
"EmployeeId": "23",
"Name": "Ar",
"Position": "Technical",
"Image": "",
"SubordinateCount": 0,
"Subordinates": []
}
]
},
{
"EmployeeId": "24",
"Name": "Sun",
"Position": "Software Developer",
"Image": null,
"SubordinateCount": 1,
"Subordinates": [
{
"EmployeeId": "25",
"Name": "AAAA",
"Position": null,
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
}
]
},
{
"EmployeeId": "26",
"Name": "CCCC",
"Position": "Consultant",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "27",
"Name": "Jaaaa",
"Position": "Software Developer",
"Image": null,
"SubordinateCount": 2,
"Subordinates": [
{
"EmployeeId": "28",
"Name": "Jay",
"Position": "Ssssss",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
},
{
"EmployeeId": "29",
"Name": "NNNN",
"Position": "Sssss",
"Image": null,
"SubordinateCount": 1,
"Subordinates": [
{
"EmployeeId": "30",
"Name": "Jo",
"Position": "Engineer",
"Image": null,
"SubordinateCount": 0,
"Subordinates": []
}
]
}
]
}
]
}
This is the json to be used .I have tried with collection view inside table view.But failed when i try to delete a row when user moves to the top and clicks on a new person . I have seen many libraries showing tree structure for table view . But i think that cannot be used here .
This is what i have tried so far.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedIndexes.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var bottomCell : SubordinatesTableViewCell! = self.Extableview.dequeueReusableCell(withIdentifier: "SubordinatesTableViewCell") as? SubordinatesTableViewCell
if bottomCell == nil {
let nib:Array = Bundle.main.loadNibNamed("SubordinatesTableViewCell", owner: self, options: nil)!
bottomCell = nib[0] as? SubordinatesTableViewCell
}
bottomCell.empLevel = indexPath.row
bottomCell.delegate = self
bottomCell.subordinateDetails = self.subordinatesList
return bottomCell
}
extension CurrentVC : SubordinateCellDelegate {
func employeeClicked(row: Int?, index: Int?) {
self.subordinatesList = self.heirarchy?.subordinates
self.currentHeirarchyLevel = row! + 1
if self.Extableview.numberOfRows(inSection: 0) > row! + 1 {
var newIndexes = [Int]()
if row! == 0 {
self.selectedIndexes.removeAll()
self.selectedIndexes.append(index!)
}else {
for i in 0..<(row! + 1) {
newIndexes.append(selectedIndexes[i])
}
self.selectedIndexes = newIndexes
self.selectedIndexes.append(index!)
}
for i in 0..<row! + 1 {
self.subordinatesList = self.subordinatesList?[self.selectedIndexes[i]].subordinates
print(subordinatesList)
}
if subordinatesList?.count ?? 0 > 0 {
self.Extableview.reloadRows(at: [IndexPath(row: self.currentHeirarchyLevel, section: 0)], with: .fade)
}else {
for i in 0..<self.Extableview.numberOfRows(inSection: 0) {
if i > row! {
self.Extableview.beginUpdates()
self.Extableview.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .fade)
}
}
self.numOfsections = row! + 1
self.Extableview.endUpdates()
}
}else {
self.selectedIndexes.append(index!)
for i in 0..<row! + 1 {
self.subordinatesList = self.subordinatesList?[self.selectedIndexes[i]].subordinates
}
if self.subordinatesList?.count ?? 0 > 0 {
self.Extableview.beginUpdates()
self.numOfsections = row! + 2
self.Extableview.insertRows(at: [IndexPath(row: row! + 1, section: 0)], with: .none)
self.Extableview.endUpdates()
}else {
for i in 0..<self.Extableview.numberOfRows(inSection: 0) {
if i > row! {
self.Extableview.beginUpdates()
self.numOfsections = row! + 1
self.Extableview.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .fade)
}
}
self.Extableview.endUpdates()
}
}
}
}
Declare 4 variables ,
var heirarchy : Subordinates?
var numOfRows = 0
var subordinatesList : [Subordinates]?
var subList = [[Subordinates]?]()
Once you get the json response ,
self.numOfRows += 1
self.subordinatesList?.append(self.heirarchy!)
self.subList.append([self.heirarchy!])
Create a delegate function for collection view item click as below .
func employeeClicked(row: Int?, index: Int?, subordinates: [Subordinates]?) {
if (subordinates?.count ?? 0) > 0 {
self.subordinatesList = subordinates
if numOfRows > row! + 2 {
self.tableView.beginUpdates()
for i in (row! + 1)..<tableView.numberOfRows(inSection: 0) {
self.tableView.deleteRows(at: [IndexPath(row: i, section: 0)], with: .fade)
self.numOfRows = numOfRows - 1
self.subList.removeLast()
}
self.subList.append(self.subordinatesList)
self.numOfRows = row! + 2
self.tableView.insertRows(at: [IndexPath(row: row! + 1, section: 0)], with: .fade)
self.tableView.endUpdates()
}
else if numOfRows == row! + 2 {
self.subList[row! + 1] = self.subordinatesList
self.tableView.reloadRows(at: [IndexPath(row: row! + 1, section: 0)], with: .fade)
}else {
self.subList.append(self.subordinatesList)
self.numOfRows = row! + 2
self.tableView.insertRows(at: [IndexPath(row: row! + 1, section: 0)], with: .fade)
}
}else {
if numOfRows > row! + 1 {
self.tableView.beginUpdates()
for i in (row! + 1)..<tableView.numberOfRows(inSection: 0) {
self.tableView.deleteRows(at: [IndexPath(row: i, section: 0)], with: .fade)
self.numOfRows = numOfRows - 1
self.subList.removeLast()
}
self.tableView.endUpdates()
}
}
self.tableView.scrollToBottom()
}
}
In tableview cellfor row delegate use the value of sublist array.
Hope this helps you . I checked the code and it is working fine for me.
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.
I have problem with parse json to collectionview
That is my JSON:
{
"statusCode": 200,
"message": "Список курсов",
"content": [
{
"id": 1,
"slug": "kurs-a1",
"title": "Курс А1",
"can_access": 1,
"passed": 1,
"sections": [
{
"id": 1,
"slug": "razdel-1",
"title": "Раздел 1",
"can_access": 1,
"passed": 1,
"lessons": [
{
"id": 1,
"position": 1,
"title": "Сәлемдесу",
"slug": "salemdesu",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 1,
"passed": 1
},
{
"id": 3,
"position": 2,
"title": "Танысу",
"slug": "tanysu",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 1,
"passed": 1
}
]
},
{
"id": 2,
"slug": "razdel-2",
"title": "Раздел 2",
"can_access": 1,
"passed": 0,
"lessons": [
{
"id": 4,
"position": 3,
"title": "Бұл – менің отбасым",
"slug": "bul-menin-otbasym",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 1,
"passed": 0
},
{
"id": 5,
"position": 4,
"title": "Жасы нешеде?",
"slug": "zhasy-neshede",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 1,
"passed": 0
}
]
},
{
"id": 3,
"slug": "razdel-3",
"title": "Раздел 3",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 7,
"position": 5,
"title": "Туған күн",
"slug": "tugan-kun",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 9,
"position": 6,
"title": "Құттықтау",
"slug": "kuttyktau",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 4,
"slug": "razdel-4",
"title": "Раздел 4",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 10,
"position": 7,
"title": "Адам келбеті",
"slug": "adam-kelbeti",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 12,
"position": 8,
"title": "Адамның мінез-құлқы",
"slug": "adamnyn-minez-kulky",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 5,
"slug": "razdel-5",
"title": "Раздел 5",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 13,
"position": 9,
"title": "Менің мамандығым",
"slug": "menin-mamandygym",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 15,
"position": 10,
"title": "Кім болып жұмыс істейді?",
"slug": "kim-bolyp-zhumys-istejdi",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 6,
"slug": "razdel-6",
"title": "Раздел 6",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 16,
"position": 11,
"title": "Жұмыс орны",
"slug": "zhumys-orny",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 17,
"position": 12,
"title": "Жұмыс күні",
"slug": "zhumys-kuni",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 7,
"slug": "razdel-7",
"title": "Раздел 7",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 19,
"position": 13,
"title": "Тесты ЦОР-а",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 20,
"position": 14,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 8,
"slug": "razdel-8",
"title": "Раздел 8",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 22,
"position": 15,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 23,
"position": 16,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 9,
"slug": "razdel-9",
"title": "Раздел 9",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 25,
"position": 17,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 27,
"position": 18,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 10,
"slug": "razdel-10",
"title": "Раздел 10",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 28,
"position": 19,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 29,
"position": 20,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 11,
"slug": "razdel-11",
"title": "Раздел 11",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 32,
"position": 21,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 33,
"position": 22,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
},
{
"id": 12,
"slug": "razdel-12",
"title": "Раздел 12",
"can_access": 0,
"passed": 0,
"lessons": [
{
"id": 34,
"position": 23,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
},
{
"id": 35,
"position": 24,
"title": "Тесты",
"slug": "testy",
"image": "https://tilqural.kz/assets/img/default-lesson-icon.png",
"can_access": 0,
"passed": 0
}
]
}
]
}
]
}
I decode it and i want parse it to collectionview.
How can i get content [{sections[{lessons[{title}]}]}]?
I made a request
func numberOfSections(in collectionView: UICollectionView) -> Int {
return arrData1.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let dn = arrData1[section]
let st = dn.sections?[section]
return (st?.lessons?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "main_cell", for: indexPath) as! MainCollectionViewCell
cell.lesson_text_1.text = arrData1.first?.sections?[indexPath.item].title
// cell.lesson_img_1.image = UIImage(named: lesson_image_1[indexPath.row])
// cell.lesson_text_1.text = lesson_text_1[indexPath.row]
return cell
}
but it return 2 cell to me
But i need 24 lessons!
Thank you
Decoding
struct Welcome: Codable {
let statusCode: Int
let message: String
let content: [Content]
}
struct Content: Codable {
let id: Int
let slug, title: String
let canAccess: Int?
let passed: Int
let sections: [Content]?
let lessons: [Lesson]?
enum CodingKeys: String, CodingKey {
case id, slug, title
case canAccess = "can_access"
case passed, sections
case lessons = "lessons"
}
}
struct Lesson: Codable {
let id, position: Int
let title, slug: String
let image: String
let canAccess: Int?
let passed: Int
enum CodingKeys: String, CodingKey {
case id, position, title, slug, image
case canAccess = "can_access"
case passed
}
}
api call function
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let data_new = try decoder.decode(Welcome.self, from: data)
DispatchQueue.main.async {
self.tableview.reloadData()
self.arrData1 = data_new.content
print(data_new)
}
} catch {
print("Error in CheckNew is : \n\(error)")
}
}
mData.resume()
enter image description here
Although the JSON structure is quite similar I recommend to use separate structs for Section and Lesson.
Another benefit is you get rid of all optionals
struct Welcome: Codable {
let statusCode: Int
let message: String
let content: [Content]
}
struct Content: Codable {
let id: Int
let slug, title: String
let canAccess: Int
let passed: Int
let sections: [Section]
}
struct Section: Codable {
let id: Int
let title, slug: String
let canAccess: Int
let passed: Int
let lessons: [Lesson]
}
struct Lesson: Codable {
let id, position: Int
let title, slug: String
let image: URL
let canAccess: Int
let passed: Int
}
As you are using the .convertFromSnakeCase strategy all coding keys are redundant.
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": []
}
]
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: ", ")