skip to Main Content

currently I am trying to implement my search bar, but something is wrong and I can’t figure it out what it is. Here is the code, and explanation.

//global variable for empty array, its type of Any cause I am getting data from network call
var filteredData: [Any]!
//these are my models, which I am using to display them on screen after mapping in network function
var bookedTrips: [BookedTripsForView]?

func viewDidLoad() {
        super.viewDidLoad()
        filteredData = bookedTrips
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBar.becomeFirstResponder()
        filteredData = []
        if searchText == "" {
            filteredData = bookedTrips
        }else {
            for trip in (bookedTrips)! {
                if trip.tripName.lowercased().contains(searchText.lowercased()){
                    filteredData.append(trip)
                  //if I type, lets say Barcelona, in console its printed correct result, 
                  //but its displaying only first trip in my array, which is Berlin
                    print("filteredDataArray after appending print: (String(describing: filteredData))")
                }
            }
        }
        self.tableView.reloadData()
    }

I hope that my explanation is ok, if something’s not clear, I will refactor my question. Thanks in advance.

Here is picture of my screen and console

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if let filter = filteredData {
                return filter.count
            } else if let data = bookedTrips {
                return data.count
            }
            return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
    
    if let trips = bookedTrips?[indexPath.row] {
        cell.configure(trips: trips)
    }
    return cell
}

4

Answers


  1. Chosen as BEST ANSWER

    And now, since I changed my variables to this :

    var filteredData = [BookedTripsForView]()
    var bookedTrips = [BookedTripsForView]()
    

    I have one more problem in sections, added comment inside

        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: Cells.sectionTitle) as! TripsListHeaderCell
        
        if isSearching {
            cell.configure(trips: filteredData[section])
        }
        else {
            cell.configure(trips: bookedTrips[section])
        }
        return cell
    }
    

    How should I implement function viewForHeaderInSection? In response inside every trip I get status of trip (current, upcoming, previous). I would like to sort them by status. If I put this inside viewForHeaderInSection :

    if isSearching { 
      cell.configure(trips: filteredData[section])
    } else { 
      cell.configure(trips:bookedTrips[section])
    } 
    return cell
    

    I get index out of range on bookedTrips[section] If i comment that line, it works until I make mistake in search bar, lets say instead of Barcelona I type Bars, it throws error on filteredData[section] index out of range

    In my response, every trip have trip status property which has type string, can I even sort them by that property?


  2. create enum for page mood like this for readable code:

    enum PageMood {
        
        case normal
        case search
    }
    

    and create variable

    var pageMode: PageMood = .normal
    

    set normal for first first if search and change pageMode to search like this:

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBar.becomeFirstResponder()
        if searchText == "" {
            pageMode = .normal
        }else {
            pageMode = .search
            filteredData = bookedTrips?.filter({ item -> Bool in
                return (item.tripName?.lowercased().contains(searchText.lowercased()) ?? false)
            })
        }
        
        self.tableView.reloadData()
    }
    

    change define datasource like this:

    var bookedTrips: [BookedTripsForView]?
    var filteredData: [BookedTripsForView]?
    

    and inside set numberOfItem:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if pageMode == .search {
            return filteredData.count ?? 0
        } else {
            return bookedTrips.count ?? 0
        }
    }
    

    if only one item find، Maybe your data has only one item similar to the search text.

    Login or Signup to reply.
  3.  var isSearching: Bool = false // As global variable
     var bookedTrips: [BookedTripsForView]? = []
     var filteredData: [BookedTripsForView]? = []
    
     
     func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBar.becomeFirstResponder()
        filteredData = []
        if searchText == "" {
            isSearching = false
        }else {
            isSearching = true
            filteredData = bookedTrips.filter { (trip) -> Bool in
                if trip.tripName.lowercased().contains(searchText.lowercased()){
                    return true
                } 
                return false
        }
    
            
        }
        self.tableView.reloadData()
    }
    

    //Tableview delegate

      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
            if isSearching {
                return self.filteredData.count
            }
            return bookedTrips.count
    

    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
    
      if isSearching {
          cell.configure(trips: filteredData[indexPath.row])
      }
      else {
         cell.configure(trips: bookedTrips[indexPath.row])
    
      }
      return cell
    

    }

    Login or Signup to reply.
  4. Short and simple (One line filter)

    var filteredData = [BookedTripsForView]()
    var bookedTrips = [BookedTripsForView]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bookedTrips = fetchFromAPIorDB()
        filteredData = bookedTrips
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.filteredData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
        cell.configure(trips: filteredData[indexPath.row])
        return cell
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if searchText.isEmpty {
            filteredData = bookedTrips
        }
        else {
            filteredData = bookedTrips.filter({ $0.tripName.lowercased().contains(searchText.lowercased()) })
        }
        self.tableView.reloadData()
    }
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search