I have previously asked a question about searching for users the most cost-efficient way (without having to load up every user in the entire database.
My code before the
The code in the question is almost correct, just need to tweak it to ensure the enumeration var is a snapshot and then use it with Mapper.
As a user enters a user name, recursively call this with each keypress; so if they are typing in Leroy, L is typed first and this code will retrieve all nodes where the username value starts with "L". Then the user types 'e' making it 'Le' etc etc.
func searchUsers(text: String) {
if text.count > 0 {
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
EDIT:
OP requested code for handling the search through a searchBar and a if statement to prevent searching if there are is no text. Here's the delegate method for that which calls the searchUsers function above
func searchBar(_ searchBar: UISearchBar,
textDidChange searchText: String) {
self.searchUsers(text: searchText)
}
EDIT:
OP wanted to see my viewDidLoad function, as unexciting as it is, so here it is.
class ViewController: UIViewController, UISearchBarDelegate
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
I am adding this as a separate answer as the OP has additional indirectly related questions:
This is my entire codebase
class ViewController: UIViewController, UISearchBarDelegate {
@IBOutlet var searchBarOutlet: [UISearchBar]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate = self
}
var userNamesArray = [String]()
func searchBar(_ searchBar: UISearchBar,
textDidChange searchText: String) {
self.searchUsers(text: searchText)
}
func searchUsers(text: String) {
self.userNamesArray = []
if text.count > 0 {
let ending = text + "\u{f8ff}"
let databaseRef = self.ref.child("users")
databaseRef.queryOrdered(byChild: "Name")
.queryStarting(atValue: text)
.queryEnding(atValue: ending)
.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let childSnap = child as! DataSnapshot
let userName = childSnap.childSnapshot(forPath: "Name").value as! String
self.userNamesArray.append(userName)
}
print(self.userNamesArray) //here you would call tableView.reloadData()
})
}
}
}
That's it other than assigning self.ref to my Firebase. My structure is:
users
uid_0
name: "Frank"
uid_1
name: "Fred"
uid_2
name: "Finay"
etc when I type in the search field 'F' I get the following output
["Frank", "Fred", "Friday"]
then when I type 'Fr', I get the following output
["Frank", "Fred"]
So as you can see, it works. If it's not working in your case, you may not have your tableView connected correctly or some other issue unrelated to the search.
Now, I am not using a tableView but simply printing name strings to the console so you would need to do a tableView.reloadData() in the place of my print statement.