Google Places not loading into TableView - ios

I have a UIViewController which presents another UIViewController as a UISearchResultsController.
I would like this searchResultsController to display GooglePlaces upon search.
I am getting all the autocomplete predictions printed out in the console, however, the UITableView is not loading the data.
Here is my function;
func updateSearchResults(for searchController: UISearchController) {
searchController.searchResultsUpdater = self
if searchController.isActive {
searchController.searchResultsController?.view.isHidden = false
}
if searchController.searchBar.text == "" {
self.searchResults.removeAll()
} else {
guard let query = searchController.searchBar.text else { return }
GMSPlacesClient.shared().autocompleteQuery(query, bounds: nil, filter: filteredResults) { (predictions, error) in
if error != nil {
print(error as Any)
return
} else {
guard let searchPredictions = predictions else { return }
self.searchResults = searchPredictions
print("PREDICTION: \(searchPredictions)")
DispatchQueue.main.async {
self.resultsTableView.reloadData()
}
}
}
}
}
Sanitation Checks
TableView Delegate
TableView DataSource
Predictions
numberOfRowsInSection
1 & 2 are set to self.
3 is printing;
GMSAutocompletePrediction 0x6000037f0450: "England Street, Charlotte, NC, USA", id: EiJFbmdsYW5kIFN0cmVldCwgQ2hhcmxvdHRlLCBOQywgVVNB, types: (
route,
geocode
4 is giving me the correct amount of predictions
I am following the custom implementation from google here;
https://developers.google.com/places/ios-sdk/autocomplete#get_place_predictions_programmatically
Under 'Get place predictions programmatically'
As always any help appreciated.
Update: TableView Methods
extension SearchResultsController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let resultsCell = resultsTableView.dequeueReusableCell(withIdentifier: resultsCellIdentifier, for: indexPath) as! ResultsCell
let resultsAttributedFullText = searchResults[indexPath.row].attributedFullText.string
resultsCell.textLabel?.text = resultsAttributedFullText
return resultsCell
}
UPDATE: cellForRowAt
Upon further inspection of my cellForRowAt function;
let results = searchResults[indexPath.row].placeID
printing results to the console doesn't give me any output.
UPDATE:
Adding breakpoint result at self.searchResults = searchPredictions
UPDATE:
In the console I'm getting the following error;
[BoringSSL] nw_protocol_boringssl_get_output_frames(1300) [C3.1:2][0x7ffd627057e0] get output frames failed, state 8196
Not sure if this could be connected to my issue or not but noting it anyway.

Could you replace the following:
DispatchQueue.main.async {
self.resultsTableView.reloadData()
}
to
DispatchQueue.main.async {
searchController.searchResultsController.resultsTableView.reloadData()
}

Related

How to optimize loading from Firestore to Tableview

My View Controller has a Tableview with 2 segments. Depending on which Segment is selected, the Tableview displays a different set of data.
#IBAction func didChangeSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
model.getRecipes(starredTrue: false)
}
else if sender.selectedSegmentIndex == 1 {
model.getRecipes(userAdded: true)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipe.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
let recipeInTable = recipe[indexPath.row]
cell.displayRecipe(recipe: recipeInTable, indexPathRow: indexPath.row)
return cell
}
And this is how model.getRecipes() gets data from Firestore before returning it to the Tableview:
let recipeQuery = db.collection("recipes")
let docRef = recipeQuery.document(documentId)
docRef.getDocument { document, error in
if let error = error as NSError? {
self.errorMessage = "Error getting document: \(error.localizedDescription)"
}
else {
if let document = document {
do {
self.recipe = try document.data(as: Recipe.self)
let recipeFromFirestore = Recipe(
id: documentId,
title: self.recipe!.title ?? "")
self.recipes.append(recipeFromFirestore)
}
catch {
}
}
DispatchQueue.main.async {
self.delegateRecipes?.recipesRetrieved(recipes: self.recipes)
}
}
}
The issue I'm having is that the Tableview takes a very long time to display data. It appears this is because it has to wait for the model to finish loading all the data from Firestore every time I select one of the segments.
How can I optimize this process? Is it possible to have the TableView load/display cell by cell, instead of needing to wait for all data to be loaded?
Any guidance is much appreciated!

Json request retrieving results but only displaying the first result

I have a tableview which is getting data from an api request, from that request its only displaying the first result.
//MARK:-- Computed vars
var listOfLodges = [LodgeDetail](){
didSet{
DispatchQueue.main.async {
self.tableView.reloadData()
self.navigationItem.title = "\(self.listOfLodges.count) lodges found"
print("\(self.listOfLodges.count) lodges found") // returns 11 lodges
print(" ")
}
}
}
this displays 11 returned results, all the data is different.
//MARK: -- ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
//MARK:-- Setting up Table view
#objc func setDelegate(){
let landing = LandingViewController()
landing.delegate = self
}
override func numberOfSections(in tableView: UITableView) -> Int {
return listOfLodges.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
this is probably where my errors are, I am unsure of what could be going wrong?
// possible errors here
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for:indexPath)
let lodge = listOfLodges[indexPath.row]
let rating: String = String(lodge.rating!)//careful force unwrapping
print(rating) // prints the same 4.2
print(lodge.name) //prints the same name
return cell
}
}
//MARK:-- Functions called on did load
extension ListViewController{
func loadData(){
let lodgeRequest = LodgeRequest(lat:passedLat, long:passedLong)
lodgeRequest.getLodges{[weak self] result in
switch result{
case.failure(let error):
print(error)
case.success(let lodges):
self?.listOfLodges = lodges
}
}
}
}
Change
let lodge = listOfLodges[indexPath.row]
to
let lodge = listOfLodges[indexPath.section]
As you only have one row per section then indexPath.row is always 0 so first item is displayed for all sections

iOS UITableView doesn't reload data when searching

I am implementing a search page like Instagram's - such that when you go to the search tab, you see trending searches (with dynamic sections) etc but when you start typing in the search box, the trending searches go away and the search results are shown.
I did just that but it doesn't seem to work.
A) No results are shown when I search for something (I log the response from the api calls - I am getting the data correctly for sure).
B) I don't go back to show trending results even after I hit cancel (Again, I print in the cancelSearch action, the function is being called for sure)
Here's a simplified version of my code:
class SearchVC: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
var sections = [String]()
var allTrendingOfferings = [[OfferingModel]]()
var allSearchResultOfferings = [OfferingModel]()
override func viewDidLoad() {
super.viewDidLoad()
sections = // data from backend
allTrendingOfferings = // data from backend
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (searchController.isActive) {
return ""
}
return self.sections[section]
}
override func numberOfSections(in tableView: UITableView) -> Int {
if (searchController.isActive) {
return 1
}
return self.sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (searchController.isActive) {
return allSearchResultOfferings.count
}
return allTrendingOfferings[section].count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "offeringCell", for: indexPath) as! SeachTVCell
if (searchController.isActive) {
let offering = allSearchResultOfferings[indexPath.row]
} else {
let offering = allTrendingOfferings[indexPath.section][indexPath.row]
}
// configure cell and
return cell
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
allSearchResultOfferings = // data fetched from backend
self.tableView.reloadData() // done asynchronously (after receiving data)
}
func searchCancel() {
self.tableView.reloadData()
}
}
extension SearchVC: UISearchResultsUpdating {
#available(iOS 8.0, *)
func updateSearchResults(for searchController: UISearchController){
if !searchController.isActive {
searchCancel()
}
filterContentForSearchText(searchText:searchController.searchBar.text!)
}
}
False alarm - Had to quit Xcode, clean and rebuild the project. It works like a charm now.

Populating Cells in a tableView from API Call

I am forced to use an asynchronous call (I guess closure in swift) to get Data I need using an SDK (APIWrapper). I'm finding that the view is being initalized before I am able to get the data that I need.
So my 1st question to y'all is, how can I get my cells to bring in the data that I need to the table view before the view loads? Then, why would I want to use an asyncronous call at this point
import APIWrapper
import UIKit
class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let provider = APIWrapper
var categories = [String]()
//define number of cells
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
categories = []
self.getCells()
print("count " , self.categories.count)
return(self.categories.count)
}
//get number of cells
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "categories")
cell.textLabel?.text = categories[indexPath.row]
return(cell)
}
private func getCells(){
provider?.getCategoriesWithCallback { (response, error) -> () in
if error == nil {
print("response ", response)
self.updateTableViewWithCategories(categories: response as! [APIWrapperCategory])
}
else {
print("FUCKK")
}
}
}
private func updateTableViewWithCategories(categories: [APIWrapperCategory]){
for category in categories{
print("category obj " , category)
print("category name " , category.name)
}
}
}
The output from my console looks like
count 0
count 0
count 0
count 0
response Optional([<APIWrapperCategory: 0x6000002a0300>])
category obj <ZDKHelpCenterCategory: 0x6000002a0300>
category name General
response Optional([<ZDKHelpCenterCategory: 0x6180002a30c0>])
category obj <ZDKHelpCenterCategory: 0x6180002a30c0>
category name General
response Optional([<ZDKHelpCenterCategory: 0x6180002a30c0>])
category obj <ZDKHelpCenterCategory: 0x6180002a30c0>
category name General
response Optional([<ZDKHelpCenterCategory: 0x6180002a3300>])
category obj <ZDKHelpCenterCategory: 0x6180002a3300>
category name General
You are getting data for your table view from the data source method of the tableview.
To get data from an API call, call self.getCells() method in viewDidLoad() method of your view controller like this:
override func viewDidLoad() {
//your code here
//get cells data
self.getCells()
}
And add your api response data to table view data source as:
private func updateTableViewWithCategories(categories: [APIWrapperCategory]){
self. categories = []
for category in categories{
print("category obj " , category)
print("category name " , category.name)
self. categories.append(category.name)
}
//reload table view here
DispatchQueue.main.async {
self.yourTableView.reloadData()
}
}
and change the delegate method as:
//define number of cells
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("count " , self.categories.count)
return(self.categories.count)
}
So I ended up using viewWillAppear and changed a few things on the way data is returned to make the cells populate so here's the code, I hope this can help someone else out
#IBOutlet weak var tableView: UITableView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.getCategoriesFromZendesk()
}
//define number of cells
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("count " , self.categories.count)
return self.categories.count
}
//get number of cells
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Add Label to the Prototype Cell
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "categories")
cell.textLabel?.text = categories[indexPath.row]
return(cell)
}
private func getCategories(){
self.categories = []
provider?.getCategoriesWithCallback { (response, error) -> () in
if error == nil {
print("response ", response?.map{($0 as AnyObject as? APIWrapperCategory)?.name ?? ""} ?? "empty")
self.updateTableViewWithCategories(categories: response as? [APIWrapperCategory])
}
else {
print("FUCKK")
}
}
}
private func updateTableViewWithCategories(categories: [APIWrapperCategory]?){
self.categories = categories?.flatMap{$0.name} ?? []
tableView.reloadData()
}

Ambiguous reference to member '(_:numberOfRowsInSection:)'

I'm trying to GET gists from Github and pop them in a table view,
here's the entire code, Gist is a class defined elsewhere:
var gists = [Gist]()
override func viewDidAppear(animated: Bool) {
loadGists()
}
func loadGists() {
GithubAPIManager.sharedInstance.fetchPublicGists() { result in
guard result.error == nil else {
print("Error 1")
return
}
if let fetchedGists = result.value {
self.gists = fetchedGists
}
self.tableView.reloadData()
//Error here.
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gists.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
let gist = gists[indexPath.row]
cell.textLabel?.text = gist.description
cell.detailTextLabel?.text = gist.ownerLogin
return cell
}
So, the problem is I didn't add an outlet of the table view to the View Controller.swift.
Just dragged the table view to the .swift file to create it.

Resources