Newbie Questions
Newbie Questions

Reputation: 463

UISearchController Filter Swift

I have a UITableViewCell with 3 subviews that I would like to filter when I search, as seen here:

TableViewCell Example

1.The image view 2.The name label (black text) 3.The street name label (blue text)

This is what I've done so far, I've only managed to understand how to filter 1 array which is the name:

MainTableView.swift

var FilteredNames = [String]

     func  updateSearchResultsForSearchController(searchController:UISearchController) {

            // Filter Names
            self.filteredNames = self.names.filter { (name:String) -> Bool in
              if name.lowercaseString.containsString(self.searchController.searchBar.text!.lowercaseString){
                    return true
                } else {
                    return false
                }
            }
            self.resultsController.tableView.reloadData()
        }
        override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
            return 100.5
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

            // Search
            if tableView == self.tableView {
                self.streets.count
               return self.names.count
            } else {
              self.filteredStreets.count
            return self.filteredNames.count
            }               
            // return names.count
            }
        
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
           
            let cell = self.tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
      
            if tableView == self.tableView {
                cell.photo.image = self.images[indexPath.row]
                cell.name.text = names[indexPath.row]
                cell.streetName.text = streets[indexPath.row]
            } else {
                cell.photo.image = self.images[indexPath.row]
                cell.name.text = self.filteredNames[indexPath.row]
                cell.streetName.text = self.streets[indexPath.row]
            }
            return cell
        }

As of right now, when I search, the image view & the street label are not synchronized with the name. I want to filter all 3 subviews to synchronize correctly. How can I achieve this?

I understand i need to use a struct and filter all 3 with one object but i'v encountered some difficulties managing to do that any help will be appreciated thank you !

Edit:here is my code right now:

    override func viewDidLoad() {
            super.viewDidLoad()

  var searchController : UISearchController!
    
    var resultsController = UITableViewController()
    
   // //
        definesPresentationContext = true
        self.resultsController.tableView.dataSource = self
        self.resultsController.tableView.delegate = self
        self.searchController = UISearchController(searchResultsController: self.resultsController)
        self.tableView.tableHeaderView = self.searchController.searchBar
        self.searchController.searchResultsUpdater = self
        self.searchController.dimsBackgroundDuringPresentation = true
        self.searchController.searchBar.sizeToFit()
        self.searchController.searchBar.barTintColor = UIColor.blackColor()
        self.searchController.searchBar.endEditing(true)
        self.searchController.searchBar.placeholder = "חפש ברים"
        

    
        allUsers = createUsers(names: names, streets: streets, images: images)
            
            filteredUsers = allUsers
            
            }
        
        var allUsers: [User]!
        var filteredUsers: [User]!
        
        func createUsers(names names: [String], streets: [String], images: [UIImage?]) -> [User] {
            var users = [User]()
            guard names.count == streets.count && names.count == images.count else { return users }
            for (index, name) in names.enumerate() {
                let user = User(name: name, streetName: streets[index], image: images[index])
                users.append(user)
            }
            return users
        }
    
    
    
    
        //MARK : Search !
        func  updateSearchResultsForSearchController(searchController:UISearchController) {
            if let searchText = searchController.searchBar.text?.lowercaseString {
                if searchText.characters.count == 0 {
                    filteredUsers = allUsers
                }
                else {
                    filteredUsers = allUsers.filter {
                        return $0.name.lowercaseString.containsString(searchText) ||
                            $0.streetName.lowercaseString.containsString(searchText)
                    }
                }
            }
            self.resultsController.tableView.reloadData()
        }
        
        override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
        {
            return 100.5;
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            ////////
            
                   ////////
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return filteredUsers.count
        }
        
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
            let cell = self.tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
            let user = filteredUsers[indexPath.row]
            cell.photo.image = user.image
            cell.name.text = user.name
            cell.streetName.text = user.streetName
            return cell
        }

Upvotes: 2

Views: 2617

Answers (1)

alexburtnik
alexburtnik

Reputation: 7741

I would strongly recommend to have only one dataSource instead of separate arrays for names, street names and images. In the following code filteredUsers is always used as dataSource and allUsers is just a stored full array, which is used for updating filteredUsers every time a new text is entered in search bar.

Create a model:

struct User {
    var name: String
    var streetName: String
    var image: UIImage?
}

ViewController:

var allUsers: [User]!
var filteredUsers: [User]!

override func viewDidLoad() {
    super.viewDidLoad()

    //assuming you already have three arrays with the same amount of elements in each:
    allUsers = createUsers(names: names, streets: streets, images: images)

    filteredUsers = allUsers
}

func createUsers(names names: [String], streets: [String], images: [UIImage?]) -> [User] {
    var users = [User]()
    guard names.count == streets.count && names.count == images.count else { return users }
    for (index, name) in names.enumerate() {
        let user = User(name: name, streetName: streets[index], image: images[index])
        users.append(user)
    }
    return users
}

func  updateSearchResultsForSearchController(searchController:UISearchController) {
    if let searchText = searchController.searchBar.text?.lowercaseString {
        if searchText.characters.count == 0 {
            filteredUsers = allUsers
        }
        else {
            filteredUsers = allUsers.filter {
                return $0.name.lowercaseString.containsString(searchText) || 
                       $0.streetName.lowercaseString.containsString(searchText)
            } ?? []
        }            
    }
    self.resultsController.tableView.reloadData()
}


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     return filteredUsers ? filteredUsers.count : 0
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
    let cell = self.tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell 
    let user = filteredUsers[indexPath.row]
    cell.photo.image = user.image
    cell.name.text = user.name
    cell.streetName.text = user.streetName
    return cell
}

Upvotes: 5

Related Questions