Why do the results of my search only show up once I begin typing?

Viewed 43

I'm implementing a search mechanism into my App, but I have encountered a problem. I can search well, and all the members of my array show up, but this only happens once I have typed something. When the view loads up, nothing appears. It is only when I start typing that anything happens. I'm not quite sure what is going wrong, so if somebody could help me out that would be fantastic. Thanks!

import UIKit
import Firebase
import FirebaseFirestore

class FindUsersTableViewController: UITableViewController, UISearchBarDelegate {

    @IBOutlet var findUsersTableView: UITableView!

    @IBOutlet weak var searchBar: UISearchBar!

    private let database = Firestore.firestore()
               private lazy var usersReference = database.collection("users")

               private let cellReuseIdentifier = "Cell"
               // This is the array that will keep track of your users, you will use it to populate your table view data:
    var usersArray = [String]()
               var filteredUsers: [String]!



    override func viewDidLoad() {
        super.viewDidLoad()

        filteredUsers = usersArray

                // Set your table view datasource and delegate:
                searchBar.delegate = self
                Firestore.firestore().collection("users").getDocuments { (snapshot, error) in
                    if let snapshot = snapshot { // don't force unwrap with !
                        for doc in snapshot.documents {
                            if let username = doc.get("username") as? String {
                                self.usersArray.append(username)
                                print(self.usersArray)

                            }
                        }
                    } else {
                        if let error = error {
                            print(error)
                        }
                    }
                }



            }



            // MARK: UITableViewDataSource methods

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

            override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                // Returns the number of users in your array:
                return filteredUsers.count

            }

            override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
                // Configure your cell here via your users array:
                cell.textLabel?.text = filteredUsers[indexPath.row]
                return cell
            }

            // MARK: UITableViewDelegate methods

            override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
                return UITableView.automaticDimension
            }


            func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
                filteredUsers = []

                if searchText == "" {
                    filteredUsers = usersArray
                }
                else {
                for info in usersArray {
                    if info.lowercased().contains(searchText.lowercased()) {
                        filteredUsers.append(info)
                    }
                }

            }
          self.tableView.reloadData()
    }
        }
2 Answers

You have to tell the table view to load the data after you have retrieved it:

override func viewDidLoad() {
    super.viewDidLoad()

    // Set your table view datasource and delegate:
    searchBar.delegate = self
    Firestore.firestore().collection("users").getDocuments { (snapshot, error) in
        if let snapshot = snapshot { // don't force unwrap with !
            for doc in snapshot.documents {
                if let username = doc.get("username") as? String {
                    self.usersArray.append(username)
                    print(self.usersArray)
                }
            }               

            // update the filteredUsers array
            filteredUsers = usersArray

            // tell the table view to reload the data here
            DispatchQueue.main.async {
                findUsersTableView.reloadData()
            }

        } else {
            if let error = error {
                print(error)
            }
        }
    }

}

Add a computed property to your code:

var isFiltering: Bool {
   return searchController.isActive && !isSearchBarEmpty
}

In the numberOfRowsInSection, do something like this:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if isFiltering {
        return filteredArray.count
    }

    return nonFilteredArray.count
}

And then in the cellForRowAt, do something like this:

func tableView(_ tableView: UITableView, 
           cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
  let tableViewArray: [String]!
  if isFiltering {
    tableViewArray = filteredArray
  } else {
    tableViewArray = nonFilteredArray
  }
  cell.textLabel?.text = tableViewArray[indexPath.row]
  return cell
}

If you want more info on the subject check this:

https://www.raywenderlich.com/4363809-uisearchcontroller-tutorial-getting-started https://developer.apple.com/documentation/uikit/uisearchcontroller

Related