fuzunspm fuzunspm - 11 days ago 8
Swift Question

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)
}
}

Answer

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()
Comments