General: I have a collections view app with several items from several plist depending which one the user picked. The plist is an array containing several arrays with multiple strings inside each array.
Problem: When inplementing a search bar to search through my collections (or plist), I get this error when following a tutorial.
I know this search bar code is meant to look for a string and not the string inside an array inside another array in the plist. So I'm looking for help to fix my error and the code.
Error:
Cannot convert value of type '[Any]' to specified type 'NSString'
This is the code what is causing the error.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filtered = car.filter({ (text) -> Bool in
let tmp: NSString = text // <-- ** Error is here **
let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.finalCollectView.reloadData()
}
Rest of my code for SearchBar
func createSearchBar() {
let mySearchBar = UISearchBar()
mySearchBar.showsCancelButton = false
mySearchBar.placeholder = "Search"
mySearchBar.delegate = self
mySearchBar.alpha = 1
mySearchBar.tintColor = UIColor.black
mySearchBar.searchFieldBackgroundPositionAdjustment = UIOffset(horizontal: 5, vertical: 0)
self.navigationItem.titleView = mySearchBar
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchActive = false;
}
Code for plist
var filtered = [[Any]]()
var searchActive: Bool = false
var car = [[Any]]()
@IBOutlet weak var finalCollectView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.finalCollectView.delegate = self
self.finalCollectView.dataSource = self
readList(titlePlist: "car")
}
func readList(titlePlist: String) {
let url = Bundle.main.url(forResource: titlePlist, withExtension: "plist")!
do {
let data = try Data(contentsOf:url)
let sections = try PropertyListSerialization.propertyList(from: data, format: nil) as! [[Any]]
car = sections
} catch {
print("This error must never occur: Reading plist", error)
}
How the plist looks like
<plist>
<array>
<array>
<string>Name1</string>
<string>Description</string>
</array>
<array>
<string>Name2</string>
<string>Description</string>
</array>
<array>
<string>Name3</string>
<string>Description</string>
</array>
</array>
</plist>
Search bar needs to search through the first string in each array. Thank you!
In your func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String), modify filtering to:
filtered = car.filter({ (anArray) -> Bool in
guard let firstString = (anArray.first as? String) else{
return false
}
let tmp: NSString = firstString as NSString
let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
If you only want to search through the first elements of the inner arrays of car, you should use flatMap to get the first elements. You should also cast the elements to NSString right away to avoid having to cast inside the filter.
filtered = car.flatMap({$0.first as? NSString})filter({ (text) -> Bool in...
However, your choice for a data structure is rather weird. Why would you declare car as [[Any]], when it only contains Strings and when the inner arrays clearly look like they should be a dictionary rather than an array? I would suggest you declare car as [[String:String]] and modify your .plist file accordingly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With