I am trying to search contact in my app. I am using search bar to do that.
Lets suppose that I have a 2 contacts, Tolga and Toygun. When I type for "To" in searchbar both contact appears in table view. Then I type for "Toy" in searchbar no one appears in table view as should be. The problem is when I delete the letter y in "Toy" no one continues to appear. I want to see both contact in table view when I delete letter y but I couldn’t.
Here is my code:
class ContactsVC: UIViewController {
//MARK: - Proporties
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var emptyView: UIView!
let fireStoreDatabase = Firestore.firestore()
var contactArray = [Contact]()
var tempContactArray = [Contact]()
var letters: [Character] = []
var tempLetters: [Character] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
hideKeyboardWhenTappedAround()
getDataFromFirebase()
}
//MARK: - Function to Get Contacts Data From Firebase
func getDataFromFirebase(){
fireStoreDatabase.collection("Contacts").order(by: "contactName").addSnapshotListener { (snapshot, err) in
if err == nil {
if snapshot?.isEmpty == false && snapshot != nil {
self.contactArray.removeAll(keepingCapacity: false)
for document in snapshot!.documents {
if let uid = document.get("uid") as? String {
if uid == self.userId {
if let contactUrl = document.get("contactUrl") as? String,
let contactName = document.get("contactName") as? String,
let contactSirname = document.get("contactSirname") as? String,
let contactPhone = document.get("contactPhone") as? String,
let contactEmail = document.get("contactEmail") as? String,
let contactBloodgroup = document.get("contactBloodGroup") as? String,
let contactBirthday = document.get("contactBirthday") as? String{
self.contactArray.append(Contact(contactUrl: contactUrl, contactName: contactName, contactSirname: contactSirname, contactPhone: contactPhone, contactEmail: contactEmail, contactBloodgroup: contactBloodgroup, contactBirthday: contactBirthday, documentId: document.documentID))
}
}
}
}
self.tempContactArray = self.contactArray
//Section
self.letters.removeAll(keepingCapacity: false)
self.letters = self.contactArray.map({ (contact) in
return contact.contactName.uppercased().first!
})
self.letters = self.letters.sorted()
self.letters = self.letters.reduce([], { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
self.tempLetters = self.letters
self.tableView.reloadData()
} else {
self.contactArray.removeAll(keepingCapacity: false)
self.tableView.reloadData()
}
if(self.contactArray.count == 0) {
self.emptyView.isHidden = false
self.tableView.isHidden = true
}else{
self.emptyView.isHidden = true
self.tableView.isHidden = false
}
}
}
}
//MARK: - Section after search
func getLetters(contact: [Contact]) {
letters.removeAll(keepingCapacity: false)
letters = contact.map({ (contact) in
return contact.contactName.uppercased().first!
})
letters = letters.sorted()
letters = letters.reduce([], { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
}
//MARK: - Table View Data Source
extension ContactsVC: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
letters.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return letters[section].description
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ContactsViewCell
if letters[indexPath.section] == contactArray[indexPath.row].contactName.uppercased().first {
cell.contactImage.sd_setImage(with: URL(string: contactArray[indexPath.row].contactUrl))
cell.contactFullNameLabel.text = contactArray[indexPath.row].contactName + " " + contactArray[indexPath.row].contactSirname
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if letters[indexPath.section] == contactArray[indexPath.row].contactName.uppercased().first {
return 100.0
} else {
return 0.0
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "AddContactVC") as! AddContactVC
vc.isNewContact = false
vc.documentId = contactArray[indexPath.row].documentId
vc.contact = contactArray[indexPath.row]
self.present(vc, animated: true, completion: nil)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
view.endEditing(true)
}
}
//MARK: - Search Bar
extension ContactsVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print(searchText)
letters.removeAll(keepingCapacity: false)
if searchText.isEmpty == false {
contactArray = contactArray.filter{$0.contactName.lowercased().contains(searchText.lowercased())}
getLetters(contact: contactArray)
} else {
contactArray = tempContactArray
letters = tempLetters
}
self.tableView.reloadData()
}
}
2
Answers
You can also implement
UISearchController
UISearchResultsUpdating
protocol with functionupdateSearchResults
and handle all your changes there. Here is a smooth tutorial: https://www.raywenderlich.com/4363809-uisearchcontroller-tutorial-getting-startedThis line causes the problem.
contactArray = contactArray.filter{$0.contactName.lowercased().contains(searchText.lowercased())}
let’s consider the same example you mentioned. You have two contacts ‘Tolgo’ and ‘Toygun’. When you type ‘To’, You filter the contacts and again assign it to the contactArray. So now contactArray will have two contacts Tolgo and Toygun. When you type ‘Toy’, again you apply filter on those 2 contacts in contactArray and assign to contactArray again. Now you will have only one contact detail ‘Toygun’ in contactArray. You are deleting ‘y’ from ‘toy’ search keyword, now you apply filter on contactArray which only has one contact(toygun). This causes only one contact to show in table
Solution:
Have all your fetched contacts in contactArray. On searching, filter from this array and assign the filtered items to tempContactArray. Have tempContactArray as the source array.
I hope i am able to help you solve your problem.