how to parse a JSON with Array of Dictionaries iOS swift - ios

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: ", ")

Related

I am trying to create a heirarchy view. The view should expand and contract once clicked on each person

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.

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": []
}
]

Decode JSON Swift 4

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)

Convert Array<CustomObject> to JSON

I hava a problem I can't convert array to JSON in SWIFT 3.0 . I am using ObjectMapper
My object
class OrderItem: Mappable {
required init?(map: Map) {
}
init() {
}
var oi_id: Int? = 0
var quantity: Double? = 0.0
var discount: Double = 0.0
var sku: Int? = 0
var orderId: Int? = 0
var Product: Product?
var isAdd: Bool = false
var isMissing: Bool!
func mapping(map: Map) {
oi_id <- map["oi_id"]
quantity <- map["quantity"]
discount <- map["discount"]
orderId <- map["orderId"]
Product <- map["Product"]
isAdd <- map["isAdd"]
isMissing <- map["isMissing"]
}}
Convert/ generating the result JSON :
var jsonArrayOrderItem = arrayOrderItem.toJSON()
Result JSON after convert . JSON is wrong :(
[["oi_id": 0, "isAdd": false, "quantity": 1.0, "Product": ["isHot": false, "discount": 50.0, "description": "description", "Acronym": "kg", "priceWithDiscount": 0.62, "bigValue": 1.0, "sku": 14, "Name": "Green Apples", "Price": 1.23, "IsFavorite": true, "smallValue": 0.20000000000000001, "Category": ["bigImageUrl": "https://i.imgur.com/7R3sFnP.png", "ImageUrl": "https://i.imgur.com/NJP4CuA.png", "cat_id": 11, "Name": "Fruits & vegetables", "Products": []], "MeasurementUnitId": 0, "ImageUrl": "https://s22.postimg.org/5992ux3j5/Green_apples.jpg", "CategoryId": 11, "Brand": ["brand_id": 8, "name": "Arbella", "imageUrl": "http://i.imgur.com/xx5ZAgL.jpg", "Products": []]], "orderId": 0, "discount": 0.0], ["oi_id": 0, "isAdd": false, "quantity": 1.0, "Product": ["isHot": false, "discount": 50.0, "description": "description", "Acronym": "kg", "priceWithDiscount": 0.62, "bigValue": 1.0, "sku": 17, "Name": "Mango", "Price": 1.23, "IsFavorite": true, "smallValue": 0.20000000000000001, "Category": ["bigImageUrl": "https://i.imgur.com/7R3sFnP.png", "ImageUrl": "https://i.imgur.com/NJP4CuA.png", "cat_id": 11, "Name": "Fruits & vegetables", "Products": []], "MeasurementUnitId": 0, "ImageUrl": "https://s22.postimg.org/4om6zb2zl/Mango.jpg", "CategoryId": 11, "Brand": ["brand_id": 8, "name": "Arbella", "imageUrl": "http://i.imgur.com/xx5ZAgL.jpg", "Products": []]], "orderId": 0, "discount": 0.0]]
try for Swift 4.0 - It has inbuilt JSONDecoder.

Resources