Ad

Display The Users Reviews In A TableView

- 1 answer

I'm trying to adding in a tableView the users reviews taken from google places API

"reviews" : [
         {
            "author_name" : "Robert Ardill",
            "author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
            "language" : "en",
            "profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
            "rating" : 5,
            "relative_time_description" : "a month ago",
            "text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
            "time" : 1491144016
         }
      ],

https://developers.google.com/places/web-service/details, for now i'm trying to add only the rating, author_name and text, this is my custom tableViewCell

import UIKit




class myReviewTableCell: UITableViewCell {


    @IBOutlet weak var revText: UITextView!
    @IBOutlet weak var revRating: UIImageView!
    @IBOutlet weak var revAuthor: UILabel!

     var place: EClass?




    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }




    func revSelect(place:Eclass) {



        NearbyPlaces.getPlaceDetails(place: place) { (place) in
            DispatchQueue.main.async {
                if let rev = place.details?["reviews"] as? [String:Any] {




                }
            }
        }
    }
}

where i need to build properly the func revSelect(place:Eclass) and after call it in my cellForRowAt. I already tried to add other parameters like

if (place.details?["website"] as? String) != nil {
                self.webButton.isHidden = false
                  }
               else {
                self.webButton.isHidden = true
            }


            if let phoneNumber = place.details?["international_phone_number"] as? String {
                self.myLabel4.text = "\(phoneNumber)"
            }
            else {
                self.myLabel4.isHidden = true
              }
         }
      }

and they work well, but reviews is an array so is different, i also tried to follow the logic of the parameters "geometry"

if let g = placeInfo["geometry"] as? [String:Any] {
            if let l = g["location"] as? [String:Double] {
                if let lat = l["lat"], let lng = l["lng"] {
                    location = CLLocationCoordinate2D.init(latitude: lat, longitude: lng)
                }
            }
        }

that i added in another class, but it did not work. So what i have to do in my func revSelect to make rev.Author.text = "author_name" , revText = "text" etc. ?? (I already asked before about this but i could not solve the problem)

//UPDATE

this is the func that i use to get place details

static func getPlaceDetails(place:EClass, completion: @escaping (EClass) -> Void) {

        guard place.details == nil else {
            completion(place)
            return
        }

        var params : [String : Any]
        params = [
            "key" : AppDelegate.googlePlacesAPIKey,
            "placeid" : place.placeId,
        ]

        Alamofire.request(googlePlaceDetailsHost, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { response in
            let value = response.result.value as? [String : Any]
            place.details = (value)?["result"] as? [String : Any]
          /*  print(((value)?["result"] as? [String : Any] ?? [String : Any]()).debugDescription) */
            completion(place)
        }
    }
Ad

Answer

You just need to research JSON parsing in Swift. This article would be a good read.

JSON is quite easy to read once you understand how it is structured. You just need to map each type properly. Swift 4 Introduced the Codable protocol which when combined with JSONDecoder give you a much better way of parsing and using this data.

struct Response: Codable {
    var reviews: [Review]
}

struct Review: Codable {

    var authorName: String
    var authorUrl: String
    var rating: Int
    var text: String

    enum CodingKeys: String, CodingKey {
        case authorName = "author_name"
        case authorUrl = "author_url"
        case rating
        case text
    }
}

let data = """
{
    "reviews" : [{
        "author_name" : "Robert Ardill",
        "author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
        "language" : "en",
        "profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
        "rating" : 5,
        "relative_time_description" : "a month ago",
        "text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
        "time" : 1491144016
    }]
}
""".data(using: .utf8)

guard let data = data else { throw NSError() }

let response = try? JSONDecoder().decode(Response.self, from: data)
let reviews = response?.reviews // array of reviews
let review = reviews?.first // first one from the list (if any)

print(review?.authorName)
print(review?.rating)

So using the example above, I have created a Review type and mapped the properties of this type to the types in the JSON response. Then we can use JSONDecoder to do the rest of the work for us.

OUTPUT:

Optional("Robert Ardill")

Optional(5)

UPDATE:

You need to do something like this, but you may need to change the structs structure based on the response values.

Alamofire.request(googlePlaceDetailsHost, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { response in
    guard let data = response.data else { throw NSError() }

    let response = try? JSONDecoder().decode(Response.self, from: data)
    let reviews = response?.reviews // array of reviews
    completion(reviews?.first)
}
Ad
source: stackoverflow.com
Ad