Reputation: 242
I've got a struct Array that I'm using to populate my tableview. But I am unable to get my searchBar to work correctly. My original searchBar code was created when I was using a more "basic" array. After converting to struct it no longer works. I am getting 3 errors from Xcode. I've identified the errors in the code with // <-- ERROR. Thanks for your help!
import UIKit
struct Material {
var name : String
var lbft : String
var gcm : String
}
class ViewController: UIViewController {
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet var tableView: UITableView!
let materialData = [
Material(name: "Acetaminohen Powder, Unmilled", lbft: "43", gcm: "0.688794"),
Material(name: "Acetylene Black, 100% Compressed", lbft: "35", gcm: "0.560646"),
Material(name: "Acetylsalicyic Acid", lbft: "20", gcm: "0.320369"),
Material(name: "Acrylamide", lbft: "34", gcm: "0.54463"),
Material(name: "Acrylic Granules, Coarse", lbft: "40", gcm: "0.64"),
Material(name: "Acrylic Granules, Fine", lbft: "36", gcm: "0.58"),
Material(name: "Acrylonitrile Butadien Styrene (Abs) Resin", lbft: "50", gcm: "0.8"),
Material(name: "Acrylonitrile Butadiene Styrene (Abs) Granules", lbft: "36", gcm: "0.58"),
Material(name: "Activated Alumina", lbft: "42.5", gcm: "0.68"),
Material(name: "Activated Carbon", lbft: "32.5", gcm: "0.52"),
Material(name: "Actylene Black", lbft: "45.5", gcm: "0.73"),
Material(name: "Aero Xanthates", lbft: "112.5", gcm: "1.8"),
Material(name: "Aerolyte", lbft: "51", gcm: "0.82"),
Material(name: "Aerosil, Fumed Silica", lbft: "32", gcm: "0.51"),
Material(name: "Aerosil, Silicon Dioxide", lbft: "30", gcm: "0.48"),
Material(name: "Alaluren", lbft: "112", gcm: "1.79")]
var searchMaterial = [String]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchMaterial.count
} else {
return materialData.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.numberOfLines = 0
if searching {
cell.textLabel?.text = searchMaterial[indexPath.row]
} else {
cell.textLabel?.text = materialData[indexPath.row] // <-- ERROR Cannot assign value of type 'Material' to type 'String'
}
return cell
}
}
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBar.setShowsCancelButton(true, animated: true)
searchMaterial = materialData.filter({$0.prefix(searchText.count) == searchText}) // <-- ERROR Cannot assign value of type '[Material]' to type '[String]'
// <-- ERROR Value of type 'Material' has no member 'prefix'
searching = true
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
searching = false
searchBar.text = ""
tableView.reloadData()
}
}
Upvotes: 0
Views: 408
Reputation: 26
Hi Sean I believe I have solved this,
Everything in your tableView delegate functions are correct
Make sure to create this var at top level
var searchMaterial = [Material]()
Then add this to your searchBar function:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard !searchText.isEmpty else {
searchMaterial = materialData
tableView.reloadData()
return // When no items are typed, load your array still
}
searchMaterial = materialData.filter({ (Material) -> Bool in
Material.title.lowercased().contains(searchText.lowercased())
})
searchBar.setShowsCancelButton(true, animated: true)
searching = true
tableView.reloadData()
Hope this helped!!!
Upvotes: 1
Reputation: 3885
do you want to search by name
? If so, you can fix the second ERROR
like this:
searchMaterial = materialData
.map({ $0.name }) // convert to [String]
.filter { $0.hasPrefix(searchText) } // search
The first one can be fixed like this:
cell.textLabel?.text = materialData[indexPath.row].name
Upvotes: 0
Reputation: 146
1) cell.textLabel?.text = materialData[indexPath.row] the materialData[indexPath.row] will provide you with an object of type Material and not string. Not sure what value you are expecting. But changing it to
materialData[indexPath.row].name
2) searchMaterial = materialData.filter({$0.prefix(searchText.count) == searchText}) // <-- ERROR Cannot assign value of type '[Material]' to type '[String]'
changing to
var searchMaterial:[Material] = []
searchMaterial = materialData.filter { $0.name.contains(searchText) }
Upvotes: 2
Reputation: 247
there is no
materialData[0] etc...
declare your array such as
var searchMaterial:[String] = []
then you can access it like
searchMaterial[indexPath.row]
Upvotes: 2