This question already has answers here:
Query based on multiple where clauses in Firebase
(8 answers)
Closed 2 years ago.
I want to know how to search for multi-entry in Firebase.
Now I only can search with one entry(activity name).
The Activity table and i marked * for which i need add to search entry:
Activity{
* act_id
* act_name
* act_region
* act_district
* act_subDistrict
* act_fee
* act_type
* act_startTime
* act_endTime
act_status
act_owner
act_intro
}
This is my search controller code. Thank you for your help.
import UIKit
import FirebaseDatabase
class SearchTableViewController: UITableViewController, UISearchResultsUpdating {
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet var searchCenterTableView: UITableView!
var userArray = [NSDictionary?]()
var filteredUsers = [NSDictionary?]()
var databaseRef = Database.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
databaseRef.child("Activity").queryOrdered(byChild: "act_name").observe(.childAdded, with: { (snapshot) in
self.userArray.append(snapshot.value as? NSDictionary)
self.searchCenterTableView.insertRows(at: [IndexPath(row: self.userArray.count-1, section: 0)], with: UITableViewRowAnimation.automatic)
}) { (error) in
print(error.localizedDescription)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != ""{
return filteredUsers.count
}
return self.userArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
}else{
user = self.userArray[indexPath.row]
}
cell.textLabel?.text = user?["act_name"] as? String
cell.detailTextLabel?.text = user?["act_subDistrict"] as? String
return cell
}
func updateSearchResults(for searchController: UISearchController) {
filterContent(searchText: self.searchController.searchBar.text!)
}
func filterContent(searchText:String){
self.filteredUsers = self.userArray.filter{ user in
let username = user!["act_name"] as? String
return(username?.lowercased().contains(searchText.lowercased()))!
}
tableView.reloadData()
}
}
func filterContent(searchText:String, entries:[String]){
self.filteredUsers = self.userArray.filter{ user in
guard let user = user as? User else { return false }
var array:[Bool] = [Bool]()
for key in entries {
let value = user[key] as? String
let entry = value?.lowercased().contains(searchText.lowercased()) ?? false
array.append(entry)
}
return(array.contains(true))
}
tableView.reloadData()
}
Related
This question already has answers here:
Searchbar filtering issue
(3 answers)
Closed 3 years ago.
I'm trying to be able to search my Firebase data using a UISearchBar in my app & I am stuck. I am successfully receiving data from Firebase in a table view. I have a memories-writing app that the user can create memories (that are shown in a tableview from the firebase). memories has a title, description, a pic and a date and I want it to be able to search memories by the title.
I have a code here that doesn't work for some reason... il'l be glad if you could help me find out what's wrong in the code or find a replacement for this code :)
MemoryTitles class:
class MemoryTitles {
var title : String
init(withTitle: String) {
self.title = withTitle
}
}
MemoryViewController:
class MemoryViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
// the filtered memories array for the search bar
var memoriesTitlesArr: [String] = []
var filteredDataa: [String] = []
// connections from storyboard to the code
#IBOutlet weak var tbl: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
// an array of memories
var memories : [Memory] = []
var ref = Database.database().reference()
let sref = Storage.storage().reference()
var lastIndex : Int = 0
var strMode : String = ""
// TableView functions
// Return the number of rows in section
// section - an index number identifying a section in tableView.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return filteredDataa.count
} else {
return memories.count
}
// return memories.count
}
// Return Cell for row function : an object inheriting from UITableViewCell
// indexPath - an index path locating a row in tableView.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "iden")
if searching {
cell?.textLabel?.text = filteredDataa[indexPath.row]
} else {
var cell : UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "iden", for: indexPath)
if cell == nil
{
cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "iden")
}
let temp = memories[indexPath.row]
cell?.textLabel?.text = temp.title
cell?.imageView?.image = temp.image
return cell!
}
return cell!
}
// Can edit row : asks the data source to verify that the given row is editable.
// indexPath - an index path locating a row in tableView.
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true // true if the row indicated by indexPath is editable; otherwise, false.
}
// Asks the data source to commit the insertion or deletion of a specified row.
// indexPath - an index path locating a row in tableView.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete // editingStyle - the cell editing style corresponding to a insertion or deletion requested for the row specified by indexPath.
{
let temp = self.memories[indexPath.row]
self.memories.remove(at: indexPath.row)
self.ref.child("MEmories/\(temp.key)").removeValue()
tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
}
}
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
let rightButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(MemoryViewController.barButtonItemClicked(_:)))
self.navigationItem.setRightBarButton(rightButton, animated: true)
// Do any additional setup after loading the view.
self.loadMemories()
self.tbl.delegate = self
self.tbl.dataSource = self
}
// click on bar-Button function
#objc func barButtonItemClicked(_ sender:UIBarButtonItem)
{
print("+ clicked") // writes "+ clicked"
let addMemoryViewController = self.storyboard?.instantiateViewController(withIdentifier: "AddMemoryViewController") as! AddMemoryViewController
self.strMode = "newMemory"
self.navigationController?.pushViewController(addMemoryViewController, animated: true)
}
// Reading from NSUserDefault (A class that provides simple storage of different data types solution.)
func readFromNSUserDefault()-> Memory?
{
let d : UserDefaults = UserDefaults.standard
let strTitle = d.object(forKey: "title") as? String
let strBody = d.object(forKey: "body") as? String
let strImageRef = d.object(forKey: "imageRef") as? String
let uid = d.object(forKey: "uid") as? String
let imageData = d.object(forKey: "imageData") as? Data
let key = d.object(forKey: "key") as? String
let date = d.object(forKey: "date") as? NSNumber
let m = Memory(title: strTitle!, body: strBody!, key: key!, uid: uid!, imageRef: strImageRef!, date: date!) // A variable from type memory
m.image = UIImage(data: imageData!)
m.key = key!
return m
}
override func viewDidAppear(_ animated: Bool) {
let d = UserDefaults.standard
let newMemory = readFromNSUserDefault()
let userAdded = d.bool(forKey: "userAdded") //key new user = true
let userEdited = d.bool(forKey: "userEdited")//key user edited = true
if self.strMode == "newMemory" && userAdded
{
self.memories.append(newMemory!)
self.tbl.reloadData()
}
else if self.strMode == "edit" && userEdited
{
memories[lastIndex] = newMemory!
self.tbl.reloadData()
}
d.set(false, forKey: "userAdded")
d.set(false, forKey: "userEdited")
d.synchronize()
self.strMode = " "
}
// loading the memories from the Database
func loadMemories()
{
let UID = Auth.auth().currentUser!.uid
self.ref.child("MEmories").queryOrdered(byChild: "uid").queryEqual(toValue: UID).observeSingleEvent(of: .value, with: {
snapShot in
if let dict = snapShot.value as? NSDictionary
{
for d in (dict as? Dictionary<String,AnyObject>)!
{
let title = d.value["title"] as?String
let body = d.value["body"] as? String
let uid = d.value["uid"] as? String
let imageRef = d.value["imageRef"] as? String
let date = d.value["date"] as? NSNumber
let m = Memory(title: title!, body: body!, uid: uid!,imageRef:imageRef!, date: date!)
m.key = d.key
let tempImageRef = self.sref.child(m.imageRef)
tempImageRef.getData(maxSize: 500*1024*1024, completion: {(data,error) in
if error == nil
{
if let imageData = data
{
m.image = UIImage(data: imageData)
self.memories.append(m)
self.tbl.reloadData()
}
}
})
self.memoriesTitlesArr.append(title!)
}
}//end of if
})
}
// Notifies the view controller that a segue is about to be performed.
// segue - The segue object containing information about the view controllers involved in the segue.
// senderThe object that initiated the segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier
{
if identifier == "goToEdit"
{
let indexPath = self.tbl.indexPathForSelectedRow
let addMemoryViewController = segue.destination as! AddMemoryViewController
self.strMode = "edit"
self.lastIndex = (indexPath?.row)!
addMemoryViewController.mode = self.strMode
addMemoryViewController.current = memories[(indexPath?.row)!]
}
}
}
var searching = false
}
extension MemoryViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredDataa = memoriesTitlesArr.filter({ $0.prefix(searchText.count)==searchText.lowercased()})
searching = true
tbl.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tbl.reloadData()
}
}
Here is how you can get that working.
1. First of all, there is no need for searching to maintain the state of searching and not searching.
2. Secondly, use filteredData as the dataSource for tableView instead of memories. filteredData will initially contain all the objects from memories, i.e.
var memories : [Memory] = []
lazy var filteredData = self.memories
The UITableViewDataSource methods will be like,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "iden") {
cell.textLabel?.text = self.filteredData[indexPath.row].title
return cell
}
return UITableViewCell()
}
Now, while searching update the filteredData with filtered memories using the relevant condition, i.e.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.filteredData = self.memories.filter({ $0.title.hasPrefix(searchText) })
//change the condition as per your requirement......
self.tbl.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = nil
self.filteredData = self.memories
self.tbl.reloadData()
}
When cancelled, refill the filteredData with the whole memories data.
I am trying to automatically reload a list when the user types into the search bar of a TableView.
I have attempted to do this using my following code. I am able to get the list but even if I type into the search bar, it doesn't "filter" the results.
class UsersTableViewController: UITableViewController, UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
//update the search results
filterContent(searchText: self.searchController.searchBar.text!)
}
#IBOutlet var usersTableView: UITableView!
let searchController = UISearchController(searchResultsController: nil)
var usersArray = [NSDictionary?]()
var filteredUsers = [NSDictionary?]()
var databaseRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
databaseRef = Database.database().reference()
let usersRef = databaseRef.child("users")
let query = usersRef.queryOrdered(byChild: "email")
query.observe(.childAdded, with: {(snapshot) in
self.usersArray.append((snapshot.value as? NSDictionary?)!)
//insert the rows
self.usersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1, section: 0)], with: UITableView.RowAnimation.automatic)
}) { (error) in
print(error.localizedDescription)
}
print("HOLAAAAAAAAAAA")
print(self.usersArray)
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if ((searchController.isActive) && (searchController.searchBar.text != "")){
return filteredUsers.count
}
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let user: NSDictionary
if ((searchController.isActive) && (searchController.searchBar.text != "")){
user = filteredUsers[indexPath.row]!
}else{
user = self.usersArray[indexPath.row]!
}
cell.textLabel?.text = user["email"] as? String
cell.detailTextLabel?.text = user["name"] as? String
return cell
}
func filterContent(searchText: String){
self.filteredUsers = self.usersArray.filter({ user in
let userEmail = user!["email"] as? String
return (userEmail != nil)
})
tableView.reloadData()
}
}
What I expect to get isle verytime that the user starts typing, the list should be displaying only the searches that match the string from the search bar. But it is not doing it.
I have made a small MVP test app with firebase. I have also made a ViewController that searches for users. But now i have to load up every user in the firebase project once the searchcontroller is clicked. And this is not very scalable. (the searchcontroller displays both the usernames of the users, and also the profile photo.
I have it so the user must type atleast two words before the searchcontroller starts showing content in the tableview. So maybe a solution is to only load the usernames upon clicked, and then only loading the profilepicture when the current user is displayed? If so , how can i achieve this?
class FollowUsersTableViewController: UIViewController{
#IBOutlet var tableView: UITableView!
private var viewIsHiddenObserver: NSKeyValueObservation?
let searchController = UISearchController(searchResultsController: nil)
var usersArray = [UserModel]()
var filteredUsers = [UserModel]()
var loggedInUser: User?
//
var databaseRef = Database.database().reference()
//usikker på den koden over
override func viewDidLoad() {
super.viewDidLoad()
//large title
self.title = "Discover"
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
} else {
// Fallback on earlier versions
}
self.tableView?.delegate = self
self.tableView?.dataSource = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
self.searchController.delegate = self;
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
self.loadProfileData()
}
func loadProfileData() {
databaseRef.child("profile").queryOrdered(byChild: "username").observe(.childAdded, with: { (snapshot) in
print(snapshot)
let userObj = Mapper<UserModel>().map(JSONObject: snapshot.value!)
userObj?.uid = snapshot.key
guard snapshot.key != self.loggedInUser?.uid else { return }
self.usersArray.append(userObj!)
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let dest = segue.destination as! UserProfileViewController
let obj = sender as! UserModel
let dict = ["uid": obj.uid!, "username": obj.username!, "photoURL": obj.photoURL, "bio": obj.bio]
dest.selectedUser = dict as [String : Any]
}
}
// MARK: - tableview methods
extension FollowUsersTableViewController: UITableViewDataSource,
UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return searchController.searchBar.text!.count >= 2 ?
filteredUsers.count : 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! FollowTableViewCell
let user = filteredUsers[indexPath.row]
cell.title?.text = user.username
if let url = URL(string: user.photoURL ?? "") {
cell.userImage?.sd_setImage(with: url, placeholderImage:
#imageLiteral(resourceName: "user_male"), options:
.progressiveDownload, completed: nil)
cell.userImage.sd_setIndicatorStyle(.gray)
cell.userImage.sd_showActivityIndicatorView()
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath:
IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath) {
self.performSegue(withIdentifier: "user", sender: self.filteredUsers[indexPath.row])
}
}
// MARK: - search methods
extension FollowUsersTableViewController:UISearchResultsUpdating,
UISearchControllerDelegate {
func updateSearchResults(for searchController: UISearchController) {
searchController.searchResultsController?.view.isHidden = false
filterContent(searchText: self.searchController.searchBar.text!)
self.tableView.reloadData()
}
func filterContent(searchText:String){
if searchText.count >= 2{
self.filteredUsers = self.usersArray.filter{ user in
return(user.username!.lowercased().contains(searchText.lowercased()))
}
}
}
}
You can use queryStartingAtValue:
func searchQueryUsers(text: String, completion: #escaping (_ userNames: [String]) -> Void) {
var userNames: [String] = []
databaseRef.child("profile").queryOrdered(byChild: "username").queryStarting(atValue: text).observeSingleEvent(of: .value, with: { snapshot in
for item in snapshot.children {
guard let item = item as? DataSnapshot else {
break
}
//"name" is a key for name in FirebaseDatabese model
if let dict = item.value as? [String: Any], let name = dict["name"] as? String {
userNames.append(name)
}
}
completion(userNames)
})
}
i made a SearchViewController that searches for users, but then I started adding it so the tableview doesn't display until the user has typed at least two characters. For some odd reason, nothing shows up in the tableview when I type in two words.
Does anyone know why?
class FollowUsersTableViewController: UIViewController, UISearchBarDelegate {
#IBOutlet var tableView: UITableView!
private var viewIsHiddenObserver: NSKeyValueObservation?
let searchController = UISearchController(searchResultsController:
nil)
var usersArray = [UserModel]()
var filteredUsers = [UserModel]()
var loggedInUser: User?
//
var databaseRef = Database.database().reference()
//usikker på den koden over
override func viewDidLoad() {
super.viewDidLoad()
//large title
self.title = "Discover"
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles =
true
} else {
// Fallback on earlier versions
}
self.tableView?.delegate = self
self.tableView?.dataSource = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
self.searchController.delegate = self;
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
//self.loadProfileData()
//self.searchBar(searchController.searchBar, textDidChange: searchController.searchBar.text)
}
func searchUsers(text: String) {
if text.count >= 2 {
self.usersArray = [] //clear the array each time
let endingText = text + "\u{f8ff}"
databaseRef.child("profile").queryOrdered(byChild: "username")
.queryStarting(atValue: text)
.queryEnding(atValue: endingText)
.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let childSnap = child as! DataSnapshot
let userObj = Mapper<UserModel>().map(JSONObject:
childSnap.value!)
userObj?.uid = childSnap.key
if childSnap.key != self.loggedInUser?.uid {
//ignore this user
self.usersArray.append(userObj!)
}
}
self.tableView.reloadData()
})
}
} //may need an else statement here to clear the array when there is
no text
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let dest = segue.destination as! UserProfileViewController
let obj = sender as! UserModel
let dict = ["uid": obj.uid!, "username": obj.username!,
"photoURL": obj.photoURL, "bio": obj.bio]
dest.selectedUser = dict as [String : Any]
}
}
// MARK: - tableview methods
extension FollowUsersTableViewController: UITableViewDataSource,
UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return searchController.searchBar.text!.count >= 2 ?
filteredUsers.count : 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath) as! FollowTableViewCell
let user = filteredUsers[indexPath.row]
cell.title?.text = user.username
if let url = URL(string: user.photoURL ?? "") {
cell.userImage?.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "user_male"), options: .progressiveDownload, completed: nil)
cell.userImage.sd_setIndicatorStyle(.gray)
cell.userImage.sd_showActivityIndicatorView()
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath:
IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "user", sender: self.filteredUsers[indexPath.row])
}
}
// MARK: - search methods
extension FollowUsersTableViewController:UISearchResultsUpdating,
UISearchControllerDelegate {
func updateSearchResults(for searchController: UISearchController) {
searchController.searchResultsController?.view.isHidden = false
filterContent(searchText: self.searchController.searchBar.text!)
searchUsers(text: self.searchController.searchBar.text!)
self.tableView.reloadData()
}
func filterContent(searchText:String){
if searchText.count >= 2{
self.filteredUsers = self.usersArray.filter{ user in
return(user.username!.lowercased().contains(searchText.lowercased()))
}
}
}
}
Also worth to mention:
I didn't create the searchcontroller using storyboards, I did it programmatically.
I got the error saying
firebase [MC] Invalidating cache
before I added .indexOn in my Firebase rules, now it doesn't show up anymore - weird.
i have had this issue for a long time. The only way my searchUsers function work is when i put it in ViewDidLoad, and then change the .count to be equal or less than 0 (because its 0 by default).
But as it is right now (how i think it should work), the search dosent work.
What i want it to do is :
Only start the firebase search for users when the user has typed at least two letters (so it only searches for the users when the user has started typing, and only showing and loading the relevant data).
Also update the tableview along with filtering the search.
This is my code:
import UIKit
import FirebaseDatabase
import Firebase
import SDWebImage
import ObjectMapper
class FollowUsersTableViewController: UIViewController {
#IBOutlet var tableView: UITableView!
private var viewIsHiddenObserver: NSKeyValueObservation?
let searchController = UISearchController(searchResultsController: nil)
var usersArray = [UserModel]()
var filteredUsers = [UserModel]()
var loggedInUser: User?
//
var databaseRef = Database.database().reference()
//usikker på den koden over
override func viewDidLoad() {
super.viewDidLoad()
//large title
self.title = "Discover"
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
} else {
// Fallback on earlier versions
}
self.tableView?.delegate = self
self.tableView?.dataSource = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
self.searchController.delegate = self;
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
//self.loadProfileData()
//self.searchBar(searchController.searchBar, textDidChange: searchController.searchBar.text)
}
func searchUsers(text: String) {
if text.count >= 2 {
self.usersArray = [] //clear the array each time
let endingText = text + "\u{f8ff}"
databaseRef.child("profile").queryOrdered(byChild: "username")
.queryStarting(atValue: text)
.queryEnding(atValue: endingText)
.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let childSnap = child as! DataSnapshot
print(childSnap)
let userObj = Mapper<UserModel>().map(JSONObject: childSnap.value!)
userObj?.uid = childSnap.key
if childSnap.key != self.loggedInUser?.uid { //ignore this user
self.usersArray.append(userObj!)
}
}
self.tableView.reloadData()
})
}
} //may need an else statement here to clear the array when there is no text
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let dest = segue.destination as! UserProfileViewController
let obj = sender as! UserModel
let dict = ["uid": obj.uid!, "username": obj.username!, "photoURL": obj.photoURL, "bio": obj.bio]
dest.selectedUser = dict as [String : Any]
}
}
// MARK: - tableview methods
extension FollowUsersTableViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchController.searchBar.text!.count >= 2 ? filteredUsers.count : 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! FollowTableViewCell
let user = filteredUsers[indexPath.row]
cell.title?.text = user.username
if let url = URL(string: user.photoURL ?? "") {
cell.userImage?.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "user_male"), options: .progressiveDownload, completed: nil)
cell.userImage.sd_setIndicatorStyle(.gray)
cell.userImage.sd_showActivityIndicatorView()
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "user", sender: self.filteredUsers[indexPath.row])
}
}
// MARK: - search methods
extension FollowUsersTableViewController:UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar,
textDidChange searchText: String) {
self.searchUsers(text: searchText)
}
func updateSearchResults(for searchController: UISearchController) {
searchController.searchResultsController?.view.isHidden = false
filterContent(searchText: self.searchController.searchBar.text!)
self.tableView.reloadData()
}
func filterContent(searchText:String){
if searchText.count >= 2{
self.filteredUsers = self.usersArray.filter{ user in
return(user.username!.lowercased().contains(searchText.lowercased()))
}
}
}
}
You need to set
searchController.searchBar.delegate = self
You conform to UISearchResultsUpdating and implement updateSearchResults but it doesn't call func searchUsers(text: String)
and conform to UISearchControllerDelegate that has no relation to the search look to it's methods Here