Reputation: 6324
I have a table view which get the json data from my server.
Now I want to add a search bar using SearchContoller
. The cells (custom) are correctly displayed before the search:
but when I start typing nothing is shown. Here is the code:
MODEL
import Foundation
class PreviousLocations:NSObject{
let locationId: String?
let locationName: String?
let locationCity:String?
let locationCountry:String?
let locationLatitude:String?
let locationLongitude:String?
let sport:String?
init(dictionary:NSDictionary) {
locationId = dictionary["locationId"] as? String
locationName = dictionary["locationName"] as? String
locationCity = dictionary["locationCity"] as? String
locationCountry = dictionary["locationCountry"] as? String
sport = dictionary["sport"] as? String
locationLatitude = dictionary["locationLatitude"] as? String
locationLongitude = dictionary["locationLongitude"] as? String
}
}
Then in PreviousLocationsViewControllors
var previousLocation = [PreviousLocations]()
var filteredPreviousLocations = [PreviousLocations]()
fun tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
if section == 1{
if (self.searchController.active) {
return filteredPreviousLocations.count
}else{
return previousLocation.count
}
}
return 1
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
if indexPath.section == 0{
let addLocationCell = self.tableView.dequeueReusableCellWithIdentifier("addLocationCell", forIndexPath: indexPath)
addLocationCell.textLabel?.text = "Add Location"
return addLocationCell
}else{
var locCells:PreviousLocationsTableCell
let locations : PreviousLocations
if (self.searchController.active) {
locCells = self.tableView.dequeueReusableCellWithIdentifier("previousLocationCell") as! PreviousLocationsTableCell
locations = filteredPreviousLocations[indexPath.row]
locCells.useLocations(locations)
}else{
locCells = self.tableView.dequeueReusableCellWithIdentifier("previousLocationCell", forIndexPath: indexPath) as! PreviousLocationsTableCell
locations = previousLocation[indexPath.row]
locCells.useLocations(locations)
}
return locCells
}
}
//MARK: - Search
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredPreviousLocations.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF.locationName == %@", searchController.searchBar.text!)
let array = (previousLocation as NSArray).filteredArrayUsingPredicate(searchPredicate)
print(array)
filteredPreviousLocations = array as! Array
self.tableView.reloadData()
}
and the custom Cell
import UIKit
import QuartzCore
class PreviousLocationsTableCell: UITableViewCell {
@IBOutlet weak var conteningView: UIView!
@IBOutlet weak var locatioNameLabel: UILabel!
@IBOutlet weak var locationCityLabel: UILabel!
@IBOutlet weak var sportImage: UIImageView!
func useLocations(location:PreviousLocations) {
conteningView.layer.masksToBounds = true
conteningView.exclusiveTouch = false
// Fill in the data
locatioNameLabel.text = location.locationName
locationCityLabel.text = location.locationCity
let imageSport = UIImage(named: "\(location.sport!).png")
sportImage.image = imageSport
func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
}
If I try do change this
`filteredPreviousLocations = array as! Array`
into this
`filteredPreviousLocations = array as! [String]`
as explained in this in This tutorial, I get the error
Cannot assign a value of type '[String]' to a value of type '[PreviousLocations]'
Upvotes: 0
Views: 582
Reputation: 285069
The types of the properties are clearly defined as [PreviousLocations]
, so you don't need to cast the types except in the filter line. The format string is supposed to be locationName == %@
.
func updateSearchResultsForSearchController(searchController: UISearchController)
{
let searchPredicate = NSPredicate(format: "locationName == %@", searchController.searchBar.text!)
filteredPreviousLocations = (previousLocation as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.tableView.reloadData()
}
Alternatively you can filter with Swift's filter
function.
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredPreviousLocations = previousLocation.filter { $0.locationName == searchController.searchBar.text!}
self.tableView.reloadData()
}
As in both functions the array filteredPreviousLocations
is set distinctly, calling removeAll
is not needed, too
Edit: to get search results before typed the complete name you should filter for a partial string rather than the whole location name
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredPreviousLocations = previousLocation.filter { $0.locationName.rangeOfString(searchController.searchBar.text!, options: [.AnchoredSearch, .CaseInsensitiveSearch, .DiacriticInsensitiveSearch]) != nil}
self.tableView.reloadData()
}
Upvotes: 2