Venkatesh Chejarla
Venkatesh Chejarla

Reputation: 444

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

Upvotes: 1

Views: 5722

Answers (1)

Razib Mollick
Razib Mollick

Reputation: 5052

[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": "[email protected]",
        "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": "[email protected]",
        "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: ", ")

Upvotes: 1

Related Questions