0
votes

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.

2

2 Answers

1
votes

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.

0
votes
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()

    }