Search code examples
iosswiftswift3tableviewsearchbar

Swift Search Bar with Multiple Data


I have 5 labels that receive data from an array of SQL Query, in each cell on a tableView. I want to implement the search bar on it. Search bar should search through 1 specific label's data. it's working and filtering that specific label but when it's filtered, other 4 labels won't update and they are not changing at all. I can't figure it out. Since I have only 1 filtered data from search bar entry, I don't know how should I filter others. Thanks

EDIT: Still can't figure it out about classes and adding data and i have an error of

"Value of type '[String]' has no member 'localizedCaseInsensitiveContains'"

on searchbar function

import UIKit

class TableViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {

var data:[MyData] = []
@IBOutlet weak var searchBar: UISearchBar!
var searchActive : Bool = false
var filtered:[MyData] = []

@IBAction func sqlExecute(_ sender: AnyObject) {

var client = SQLClient()
    client.connect("sql_ip", username: "username", password: "password", database: "database") {
        success in

        if success {
            client.execute("sql query") {
                result in

                for table in result as Any as! NSArray {
                    for row in table as! NSArray {
                        for column in row as! NSDictionary {

                            if column.key as! String == "data1" {
                                MyData.init(data1: "\(column.value)")
                            } else if column.key as! String == "data2" {
                                MyData.init(data2: column.value as! Double)
                            } else if column.key as! String == "data3" {
                                MyData.init(data3: "\(column.value)")
                            } else if column.key as! String == "data4" {
                                MyData.init(data4: "\(column.value)")
                            } else if column.key as! String == "data5" {
                                MyData.init(data5: "\(column.value)")
                            }
                        }
                    }
                }
                client.disconnect()
                self.tableView.reloadData()
            }
        }
    }
}
override func viewDidLoad() {
    super.viewDidLoad()


    tableView.delegate = self
    tableView.dataSource = self
    searchBar.delegate = self
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}


override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if(searchActive) {
        return filtered.count
    } else {
        return data.count
    }
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "segue", for: indexPath)

    if(searchActive) {

        cell.label1.text = "\(filtered[indexPath.row])"
        cell.label2.text = "\(filtered[indexPath.row])"
        cell.label3.text = "\(filtered[indexPath.row])"
        cell.label4.text = "\(filtered[indexPath.row])"
        cell.label5.text = "\(filtered[indexPath.row])"
    } else {

    cell.label1.text = "\(data[indexPath.row])"
    cell.label2.text = "\(data[indexPath.row])"
    cell.label3.text = "\(data[indexPath.row])"
    cell.label4.text = "\(data[indexPath.row])"
    cell.label5.text = "\(data[indexPath.row])"
    }
    cell.backgroundColor = UIColor.clear
    cell.selectionStyle = UITableViewCellSelectionStyle.none
    return cell
}


func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    searchActive = true;
}

func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchActive = false;
    self.searchBar.endEditing(true)
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searchActive = false;
    self.searchBar.endEditing(true)
}

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    searchActive = false;
    self.searchBar.endEditing(true)
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

    filtered = data.filter { $0.data1.localizedCaseInsensitiveContains(searchText) }
    if(filtered.count == 0){
        searchActive = false;
    } else {
        searchActive = true;
    }
    self.tableView.reloadData()
}

This is the class file:

import Foundation

class MyData {
var data1 = [String]()
var data2 = [Double]()
var data3 = [String]()
var data4 = [String]()
var data5 = [String]()


init(data1: String) {
    self.data1.append(data1)
}
init(data2: Double) {
    self.data2.append(data2)
}
init(data3: String) {
    self.data3.append(data3)
}
init(data4: String) {
    self.data4.append(data4)
}
init(data5: String) {
    self.data5.append(data5)
}
}

Solution

  • Your problem is you have five different Array instead of that you need to have single Array of type Dictionary or maybe custom Struct/class. It is batter if you use struct/class like this.

    class MyData {
        var data1: String!
        var data2: Double!
        var data3: String!
        var data4: String!
        var data5: String! 
    
        init(data1: String, data2: Double, data3: String, data4: String, data5: String) {
             self.data1 = data1
             self.data2 = data2
             self.data3 = data3
             self.data4 = data4
             self.data5 = data5
        }
    }
    

    Now instead of having five different array and one for filter create two Array of type [MyData] one of them is used for showing filterData and use that with tableView methods and filter it like this.

    Create object of MyData using init method it and append its to the data Array then filter your in searchBar delegate like this.

    filtered = data.filter { $0.data1.localizedCaseInsensitiveContains(searchText) }
    

    The above filter will search in data array and return all objects thats property data1 contains searchText.

    Your whole code would be like this

    import UIKit
    
    class TableViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
    
        var data:[MyData] = []
    
        @IBOutlet weak var searchBar: UISearchBar!
        var searchActive : Bool = false
        var filtered:[MyData] = []
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
    
            tableView.delegate = self
            tableView.dataSource = self
            searchBar.delegate = self
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
    
        override func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if(searchActive) {
                return filtered.count
            } else {
                return data.count
            }
        }
    
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "segue", for: indexPath)
    
            if(searchActive) {
    
                cell.label1.text = filtered[indexPath.row].data1
                cell.label2.text = filtered[indexPath.row].data2
                cell.label3.text = filtered[indexPath.row].data3
                cell.label4.text = "\(filtered[indexPath.row].data4) ₺"
                cell.label5.text = filtered[indexPath.row].data5
            } else {
    
                cell.label1.text = data[indexPath.row].data1
                cell.label2.text = data[indexPath.row].data2
                cell.label3.text = data[indexPath.row].data3
                cell.label4.text = "\(data[indexPath.row].data4) ₺"
                cell.label5.text = data[indexPath.row].data5
            }
            cell.backgroundColor = UIColor.clear
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        }
    
    
        func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
            searchActive = true;
        }
    
        func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
            searchActive = false;
            self.searchBar.endEditing(true)
        }
    
        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            searchActive = false;
            self.searchBar.endEditing(true)
        }
    
        func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
            searchActive = false;
            self.searchBar.endEditing(true)
        }
    
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    
            filtered = data.filter { $0.data1.localizedCaseInsensitiveContains(searchText) }
            if(filtered.count == 0){
                searchActive = false;
            } else {
                searchActive = true;
            }
            self.tableView.reloadData()
        }
    }
    

    Edit: You need to use single array like this way.

    for table in result as Any as! NSArray {
        for row in table as! NSArray {
            if let dic = row as? [String : Any] {
                let data1 = dic["data1"] as! String
                let data2 = dic["data2"] as! Double
                let data3 = dic["data3"] as! String
                let data4 = dic["data4"] as! String
                let data5 = dic["data5"] as! String
                let newData =  MyData(data1: data1, data2: data2, data3: data3, data4: data4, data5: data5)
                self.data.append(newData)
            }
        }
    }
    self.tableView.reloadData()