I started a table view with a list of universities and created a search bar to tag along with it. The search bar works but only if I type in the name of the school exactly how it is. Is there a way I can change the it to search any part of the name and get the same results? Here's the code that I have set up.
#IBOutlet weak var schoolSearch: UISearchBar!
#IBOutlet weak var tblView: UITableView!
let schoolnames = ["Long Beach City College LAC", "California State University, Bakersfield", ...]
var searchedSchool = [String]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
schoolSearch.delegate = self
self.tblView.delegate = self
self.tblView.reloadData()
}
extension ChooseSchool: UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchedSchool.count
} else {
return schoolnames.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableViewCell
cell?.img.image = UIImage(named: schoolnames[indexPath.row])
cell?.lbl.text = schoolnames[indexPath.row]
_ = tableView.dequeueReusableCell(withIdentifier: "cell")
if searching {
cell?.textLabel?.text = searchedSchool[indexPath.row]
} else {
cell?.textLabel?.text = schoolnames[indexPath.row]
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "TestController") as? TestController
vc?.schoolnames = schoolnames[indexPath.row]
navigationController?.pushViewController(vc!, animated: true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchedSchool = schoolnames.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
tblView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tblView.reloadData()
}
}
Replace
searchedSchool = schoolnames.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
with
searchedSchool = schoolnames.filter { $0.range(of: searchText, options: .caseInsensitive) != nil }
I think you have to make your searchBar implement the containsString method to achieve what you need. For reference look at this link
Related
I have a Table View that is working fine. However, when I try to implement a UISearchBar and display filtered data, nothing gets filtered. This is my View Controller:
import UIKit
class MealPlanViewController: UIViewController, UISearchBarDelegate {
private var model = MealPlanModel()
private var mealPlan = [MealPlan]()
var filteredData: [MealPlan]!
#IBOutlet weak var topBarStackView: UIStackView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
model.delegate = self
searchBar.delegate = self
filteredData = mealPlan
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = []
if searchText == "" {
filteredData = mealPlan
}
else {
for item in mealPlan {
if ((item.title?.lowercased().contains(searchText.lowercased())) != nil) {
filteredData.append(item)
}
}
}
self.tableView.reloadData()
}
}
extension MealPlanViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
let filteredMealPlaninTable = filteredData[indexPath.row]
cell.displayMealPlan(filteredMealPlaninTable)
return cell
}
}
extension MealPlanViewController: MealPlanProtocol {
func mealPlansRetrieved(mealPlans: [MealPlan]) {
self.filteredData = mealPlans
tableView.reloadData()
}
}
A couple of notes:
When I run a print(self.filteredData) in my `func mealPlansRetrieved', the console returns all of my data as if it wasn't filtered, but
As soon as I start typing in the search bar, the table view doesn't return any cells, which seems contradictory to the above
For reference, this is the code before filtering that did work:
extension MealPlanViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mealPlan.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
let mealPlanInTable = mealPlan[indexPath.row]
cell.displayMealPlan(mealPlanInTable)
return cell
}
}
extension MealPlanViewController: MealPlanProtocol {
func mealPlansRetrieved(mealPlans: [MealPlan]) {
self.mealPlan = mealPlans
tableView.reloadData()
}
}
Any help/guidance is much appreciated!
Contains returns boolean so this will never fail: item.title?.lowercased().contains(searchText.lowercased())) != nil
To make check work you can simply remove "!= nil".
Im not sure from where you are calling mealPlansRetrieved, but you might want to keep the line "self.mealPlan = mealPlans" instead of "self.filteredData = mealPlans".
My app is using Firebase Realtime Database to store information of each user. The tableView works fine. I added a searchBar and when I type letters in the searchBar, I can see that the amount of rows presented in the tableView is equal to the amount of users which contain these letters in their names. The problem is that the rows presented in the tableview (after typing letters in the search bar), contain the information of the first user till x user (x = amount of users which contain these letters in their names).
import UIKit
import FirebaseDatabase
import Firebase
class VideoListScreen: UIViewController {
#IBOutlet weak var tableView: UITableView!
var blogPost: [BlogPost] = []
var searchBlogPost = [BlogPost]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
blogPost = []
createArray()
tableView.delegate = self
tableView.dataSource = self
}
func createArray() {
let ref = Database.database().reference().child("Users")
ref.observe(.childAdded, with: { (snapshot) in
if let postDict = snapshot.value as? [String : String] {
let post = BlogPost(name:postDict["name"] ?? "" , gaf: postDict["gaf"] ?? "", place: postDict["place"] ?? "", phone: postDict["phone"] ?? "", notes: postDict["notes"] ?? "", elsertext: postDict["elsertext"] ?? "")
self.blogPost.append(post)
self.tableView.reloadData()
}
})
}
}
extension VideoListScreen: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching{
return searchBlogPost.count
}else{
return blogPost.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let blogp = blogPost[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Tavla") as! Tavla
if searching{
cell.setBLogPost(blogPost: searchBlogPost[indexPath.row])
}
else{
cell.setBLogPost(blogPost: blogPost[indexPath.row])
}
cell.setBLogPost(blogPost: blogp)
return cell
}
}
extension VideoListScreen: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBlogPost = blogPost.filter({$0.name.prefix(searchText.count) == searchText})
searching = true
tableView.reloadData()
}
}
I Believe the problem is in the if and else statments in this function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let blogp = blogPost[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Tavla") as! Tavla
if searching{
cell.setBLogPost(blogPost: searchBlogPost[indexPath.row])
}
else{
cell.setBLogPost(blogPost: blogPost[indexPath.row])
}
cell.setBLogPost(blogPost: blogp)
return cell
}
You have extra cell.setBLogPost(blogPost: blogp) in your delegate methode
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let blogp = blogPost[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Tavla") as! Tavla
if searching{
cell.setBLogPost(blogPost: searchBlogPost[indexPath.row])
}
else{
cell.setBLogPost(blogPost: blogPost[indexPath.row])
}
return cell
}
I think this will solve your problem and you can use
import UIKit
import FirebaseDatabase
import Firebase
class VideoListScreen: UIViewController {
#IBOutlet weak var tableView: UITableView!
var blogPost: [BlogPost] = []
var searchBlogPost = [BlogPost]()
override func viewDidLoad() {
super.viewDidLoad()
blogPost = []
createArray()
tableView.delegate = self
tableView.dataSource = self
}
func createArray() {
let ref = Database.database().reference().child("Users")
ref.observe(.childAdded, with: { (snapshot) in
if let postDict = snapshot.value as? [String : String] {
let post = BlogPost(name:postDict["name"] ?? "" , gaf: postDict["gaf"] ?? "", place: postDict["place"] ?? "", phone: postDict["phone"] ?? "", notes: postDict["notes"] ?? "", elsertext: postDict["elsertext"] ?? "")
self.blogPost.append(post)
self.searchBlogPost = self.blogPost
self.tableView.reloadData()
}
})
}
}
extension VideoListScreen: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchBlogPost.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let blogp = searchBlogPost[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Tavla") as! Tavla
cell.setBLogPost(blogPost: blogp)
return cell
}
}
extension VideoListScreen: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if ((searchText.trimmingCharacters(in: .whitespaces).isEmpty) {
searchBlogPost = blogPost
} else {
searchBlogPost = blogPost.filter({$0.name.prefix(searchText.count) == searchText})
}
tableView.reloadData()
}
}
I hope this will helps.
I have a popup with searchBar at the top and TableView below it. TableView is populated by dynamic data. I have a custom tableViewCell, with a label for names and a checkBox(M13CheckBox Library) to select a name.
Now, when I search for a name, Firstly the tableView is not loaded as the user types a name in the search bar. For eg, Suppose there are persons named "Mary", "Mackenzie", "Margaret" and "Mallory". I want to search for "Margaret", so as I start typing "Mar" in searchBar, then "Mary" and "Margaret" are filtered properly in tableView, but when I go back i.e "Ma", then it should show all the 4 names, since "Ma" is present in the list, But the tableView does not show anything.
So tableView should always reload as user types in searchBar if the letters are contained in the names. Please help me sort this issue. Since it is a popup I am passing data to tableView from another VC, by notification.
Here is my code for search VC:
class ParticipantsListVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate{
public static var participantNameArray:[String] = [String]() //global var
var viewController: ViewController!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchParticipantFilter.delegate = self
viewController = ViewController()
let notificationName = NSNotification.Name("reloadList")
NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main) { (notifObject) in
self.tableView.reloadData()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText:String) {
if searchText == "" {
ParticipantsListVC.participantNameArray.removeAll()
viewController.getParticipantList() // func to get list from sever
}else{
ParticipantsListVC.participantNameArray = ParticipantsListVC.participantNameArray.filter({(name) -> Bool in
return name.lowercased().contains(searchText.lowercased())
})
}
self.tableView.reloadData()
}
}
Also if I select a name, then checkBox is selected in front of that name.But when I click on cancel(X) in searchBar, then always the first cell in tableView is shown selected and not the name that I had selected. I don't know why always the first cell gets selected, after selecting name from filtered list.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ParticipantListCell
let dict = ParticipantsListVC.participantNameArray[indexPath.row]
cell.participantNameLabel.text = dict
if selectedIndexPaths.contains(indexPath) {
cell.selectedParticipantCB.setCheckState(.checked, animated: true)
}else{
cell.selectedParticipantCB.setCheckState(.unchecked, animated: true)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Since any random cell was getting selected on scrolling So I added this code.
tableView.deselectRow(at: indexPath, animated: true)
if selectedIndexPaths.contains(indexPath) {
selectedIndexPaths.removeObject(object: indexPath)
}else{
selectedIndexPaths.append(indexPath)
}
tableView.reloadData()
}
I don't want to use searchBar in headerView or another tableView to show filtered list. Please much appreciated.Thank you.
You need to create another array to hold the backup of data array.
var arrParticipantList = [String]()
var arrParticipantListBackup = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.delegate = self
self.tblParticipantList.delegate = self
self.tblParticipantList.dataSource = self
self.arrParticipantList = ["Mary", "Mackenzie", "Margaret", "Mallory","Molly"]
self.arrParticipantListBackup = self.arrParticipantList
}
Code to search for search string, refill array and reload tableview
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
var searchText = searchBar.text! + text
if range.length > 0 {
if range.location == 0 {
self.arrParticipantList = self.arrParticipantListBackup
self.tblParticipantList.reloadData()
return true
}
searchText = String(searchText.dropLast(range.length))
}
self.arrParticipantList = self.arrParticipantListBackup.filter({$0.lowercased().hasPrefix(searchText.lowercased())})
self.tblParticipantList.reloadData()
return true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.searchBar.text = ""
self.searchBar.resignFirstResponder()
self.arrParticipantList = self.arrParticipantListBackup
self.tblParticipantList.reloadData()
}
}
Code for tableview
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrParticipantList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = self.arrParticipantList[indexPath.row]
return cell!
}
}
Hope this solves your issue.
struct namelist {
var searchname: NSString
}
var searchActive = Bool()
var newSearchArray = [namelist]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchActive ? newSearchArray.count : nameOldArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Cell:SearchTableViewCell! = tableView.dequeueReusableCell(withIdentifier: "Cell") as! SearchTableViewCell
Cell.selectionStyle = .none
if (searchActive == true) {
if ( newSearchArray.count > 0) {
var para = NSMutableAttributedString()
para = NSMutableAttributedString(string:(newSearchArray[indexPath.row].searchname) as String)
do {
let regex = try NSRegularExpression(pattern: searchText, options: NSRegularExpression.Options.caseInsensitive )
let nsstr = newSearchArray[indexPath.row].searchname
text = nsstr as String
let all = NSRange(location: 0, length: nsstr.length)
var matches : [String] = [String]()
regex.enumerateMatches(in: text, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: all) {
(result : NSTextCheckingResult?, _, _) in
if let r = result {
let results = nsstr.substring(with: r.range) as String
matches.append(results)
let substringrange = result!.rangeAt(0)
para.addAttribute(NSForegroundColorAttributeName, value:UIColor.init(red: 237/255.0, green: 60/255.0, blue: 58/255.0, alpha: 1.0), range: substringrange)
Cell.namelbl.attributedText = para
}
}
} catch {
}
}
}
else {
Cell.namelbl.text = self.searchname[indexPath.row] as? String
}
return Cell
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchArray.removeAllObjects()
newSearchArray.removeAll()
if Search.text != nil {
for i in 0 ..< searchname.count {
searchText = Search.text!
text = ((searchname.object(at: i))) as! String
if text.lowercased().contains(searchText.lowercased()) {
let elm = namelist(searchname: text as NSString)
self.newSearchArray.append(elm)
}
}
}
searchActive = !newSearchArray.isEmpty
searchBar.resignFirstResponder()
yourTableName.reloadData()
}
How do I get the correct viewcontroller after selecting a tableview cell can you please help me I think there is a problem with my index
import UIKit
var NamesC = [ "one", "two"]
var IndexC = 0
class ComputerVC: UIViewController ,UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var TableView: UITableView!
var data = [ "one", "two"]
var filteredData = [String]()
var inSearchMode = false
override func viewDidLoad() {
super.viewDidLoad()
TableView.delegate = self
TableView.dataSource = self
searchBar.delegate = self
searchBar.returnKeyType = UIReturnKeyType.done
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if inSearchMode {
return filteredData.count
}
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? DataCellC {
let text: String!
if inSearchMode {
text = filteredData[indexPath.row]
} else {
text = data[indexPath.row]
}
cell.congigureCell(text: text)
return cell
} else {
return UITableViewCell()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
view.endEditing(true)
TableView.reloadData()
} else {
inSearchMode = true
filteredData = data.filter({$0.contains(searchBar.text!)})
TableView.reloadData()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
IndexC = indexPath.row
performSegue(withIdentifier: "segue", sender: self)
}
}
You can try
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
var text = ""
if inSearchMode {
text = filteredData[indexPath.row]
let correctIndex = data.index(of:filteredData[indexPath.row])
print("selected value is : \(correctIndex)")
} else {
text = data[indexPath.row]
}
performSegue(withIdentifier: "segue", sender: text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondController = segue.destination as? SecondController {
secondController.sendedValue = sender as! String
}
}
class secondController:UIViewController
{
var sendedValue:String?
}
Issue is here:
Name.text = NamesC[IndexC]
Your array is filtered, your indexC is the one you used in the filtered array.
You can define a filtered array FNamesC, and update this array when you search in your search bar and in your viewController
Name.text = FNamesC[IndexC]
I don't know why you want a global array though.
I'm working on search bar with autofill feature. Sometimes I get this errors when tapping cell in autofill TableView:
*** Assertion failure in -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:],
/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UITableViewRowData.m:1849
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at
invalid index path ( {length = 2, path = 0 -
3})'
If I comment this line searchBar.text = cell.textLabel!.text app doesn't crash.
Here is full function code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell: UITableViewCell = tableView.cellForRow(at: indexPath)!
address = cell.textLabel!.text!
searchBar.text = cell.textLabel!.text
}
How can I fix it?
UPD: Looks like it crashes after searchBar.text = cell.textLabel!.text
I've added print(searchBar.text!) and it prints correct value to console
UPD2: App crashes only if I type something in search bar, then tap somewhere on the screen to dismiss keyboard, and then tap on one of autofill cells.
Class code:
import UIKit
import Alamofire
import SwiftyJSON
class StreetSelectViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationControllerDelegate
{
var data: [String] = ["Нет данных"]
var filtered: [String] = []
var searchActive : Bool = false
#IBOutlet weak var cityNameLabel: UILabel!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var topSpaceConstraint: NSLayoutConstraint!
#IBOutlet var gradientBackground: GradientView!
let segueIdentifier = "ShowStreetSelectSegue"
//background gradient
override func viewDidLayoutSubviews()
{
self.gradientBackground.create()
}
override func viewDidLoad()
{
super.viewDidLoad()
//side menu panGestureRecognizer
if self.revealViewController() != nil
{
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
tableView.tableFooterView = UIView()
navigationController?.delegate = self
//search bar settings
let barImage = UIImage()
searchBar.setBackgroundImage(barImage, for: .any, barMetrics: .default)
searchBar.scopeBarBackgroundImage = barImage
searchBar.tintColor = UIColor.lightGray
searchBar.setValue("Отмена", forKey:"_cancelButtonText")
searchBar.showsCancelButton = false
topSpaceConstraint.constant = self.navigationController!.navigationBar.frame.height + 8
//network
let queue = DispatchQueue(label: "com.admin.response-queue", qos: .utility, attributes: [.concurrent])
URLCache.shared.removeAllCachedResponses()
Alamofire.request("").validate()
.responseJSON(
queue: queue,
completionHandler: { response in
if let JSON = response.result.value
{
self.data.removeAll()
let json = SwiftyJSON.JSON(JSON)
print("JSON: \(json)")
for (_, object) in json
{
self.data.append(object.stringValue)
print(self.data)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
)
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
override func viewWillAppear(_ animated: Bool)
{
cityNameLabel.text = cityName
}
//MARK: - search bar settings
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
{
searchActive = true;
self.navigationController?.isNavigationBarHidden = true
topSpaceConstraint.constant = 8
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar)
{
searchActive = false;
self.navigationController?.isNavigationBarHidden = false
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
filtered = data
tableView.isHidden = false
tableView.reloadData()
topSpaceConstraint.constant = 8
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
if !searchActive
{
searchActive = true
tableView.reloadData()
}
self.searchBar.resignFirstResponder()
address = searchBar.text!
performSegue(withIdentifier: "ShowSearchResultsSeque", sender: Any?.self)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
filtered = data.filter({ (text) -> Bool in
let tmp: NSString = text as NSString
let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0)
{
searchActive = false;
}
else
{
searchActive = true;
}
if searchText.characters.count != 0
{
tableView.isHidden = true
}
else
{
tableView.isHidden = false
}
tableView.reloadData()
topSpaceConstraint.constant = 8
}
//MARK: - tableview settings
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if searchActive
{
if filtered.count == 0
{
return data.count
}
else
{
return filtered.count
}
}
else
{
return data.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if searchActive
{
if filtered.count == 0
{
cell.textLabel?.text = data.sorted()[indexPath.row]
}
else
{
cell.textLabel?.text = filtered.sorted()[indexPath.row]
}
}
else
{
cell.textLabel?.text = data.sorted()[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell: UITableViewCell = self.tableView.cellForRow(at: indexPath)!
address = cell.textLabel!.text!
self.searchBar.text = cell.textLabel!.text
print(searchBar.text!)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
cell.backgroundColor = UIColor.clear
//text color
cell.textLabel!.textColor = UIColor.white;
//cell selection color
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
cell.selectedBackgroundView = bgColorView
tableView.backgroundColor = UIColor.clear
}
}
Why you are using self.tableView.cellForRow in didSelectRowAt method, you can use your filtered datasource in didSelectRowAt method, which you have already used in cellForRowAt method. you can do following to achieve your functionality.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if searchActive
{
if filtered.count == 0
{
address = data.sorted()[indexPath.row]
}
else
{
address = filtered.sorted()[indexPath.row]
}
self.searchBar.text = address
}
}
I'm not sure why but the problem was in SearchDisplayController. After deleting it in storyboard everything works fine