0

I have created the search bar programatically and I am expecting to filter the data when the text is enter into search bar. Problem is not filtering the data although I have data already downloaded form api call and tried to search the text based on the title.

Here is the view model code including the search function..

import Foundation import UIKit enum MoviesViewModelState { case loading case loaded([Movie]) case error var movies: [Movie] { switch self { case .loaded(let movies): return movies case .loading, .error: return [] } } } final class MoviesViewModel { private let apiManager: APIManaging var filteredMovie: [Movie] = [] init(apiManager: APIManaging = APIManager()) { self.apiManager = apiManager } var updatedState: (() -> Void)? var state: MoviesViewModelState = .loading { didSet { updatedState?() } } func fetchData() { apiManager.execute(Movie.topRated) { [weak self] result in switch result { case .success(let page): self?.state = .loaded(page.results) case .failure: self?.state = .error } } } } // MARK: - Search function. extension MoviesViewModel { public func inSearchMode(_ searchController: UISearchController) -> Bool { let isActive = searchController.isActive let searchText = searchController.searchBar.text ?? "" return isActive && !searchText.isEmpty } public func updateSearchController(searchBarText: String?) { self.filteredMovie = state.movies if let searchText = searchBarText?.lowercased() { guard !searchText.isEmpty else { return } self.filteredMovie = self.filteredMovie.filter({ $0.title.lowercased().contains(searchText) }) } } } 

Here is the view controller code.

import UIKit final class MoviesViewController: UITableViewController { private let viewModel: MoviesViewModel // MARK: - UI Components private let searchController = UISearchController(searchResultsController: nil) init(viewModel: MoviesViewModel) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() title = LocalizedString(key: "movies.title") NotificationCenter.default.addObserver(self, selector: #selector(textSizeChanged), name: UIContentSizeCategory.didChangeNotification, object: nil) setupSearchController() configureTableView() updateFromViewModel() bindViewModel() viewModel.fetchData() } private func configureTableView() { tableView.dm_registerClassWithDefaultIdentifier(cellClass: MovieCell.self) tableView.rowHeight = UITableView.automaticDimension refreshControl = UIRefreshControl() refreshControl?.addTarget(self, action: #selector(refreshData), for: .valueChanged) } private func bindViewModel() { viewModel.updatedState = { [weak self] in guard let self else { return } DispatchQueue.main.async { self.updateFromViewModel() } } } private func updateFromViewModel() { switch viewModel.state { case .loading, .loaded: tableView.reloadData() case .error: showError() } refreshControl?.endRefreshing() } // MARK: setUpSearch Property. private func setupSearchController() { self.searchController.searchResultsUpdater = self self.searchController.obscuresBackgroundDuringPresentation = false self.searchController.hidesNavigationBarDuringPresentation = false self.searchController.searchBar.placeholder = "Search Movie" self.navigationItem.searchController = searchController self.definesPresentationContext = false self.navigationItem.hidesSearchBarWhenScrolling = false searchController.delegate = self searchController.searchBar.delegate = self searchController.searchBar.showsBookmarkButton = true searchController.searchBar.setImage(UIImage(systemName: "line.horizontal.3.decrease"), for: .bookmark, state: .normal) } private func showError() { let alertController = UIAlertController(title: "", message: LocalizedString(key: "movies.load.error.body"), preferredStyle: .alert) let alertAction = UIAlertAction(title: LocalizedString(key: "movies.load.error.actionButton"), style: .default, handler: nil) alertController.addAction(alertAction) present(alertController, animated: true, completion: nil) } @objc private func refreshData() { viewModel.fetchData() } @objc private func textSizeChanged() { tableView.reloadData() } } // MARK: - UITableViewDataSource extension MoviesViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let inSearchMode = self.viewModel.inSearchMode(searchController) return inSearchMode ? self.viewModel.filteredMovie.count : self.viewModel.state.movies.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell: MovieCell = tableView.dm_dequeueReusableCellWithDefaultIdentifier() let inSearchMode = self.viewModel.inSearchMode(searchController) let movie = inSearchMode ? self.viewModel.filteredMovie[indexPath.row] : self.viewModel.state.movies[indexPath.row] cell.configure(movie) return cell } } // MARK: - UITableViewControllerDelegate extension MoviesViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let movie = viewModel.state.movies[indexPath.row] let viewModel = MoviesDetailsViewModel(movie: movie, apiManager: APIManager()) let viewController = MovieDetailsViewController(viewModel: viewModel) self.navigationController?.pushViewController(viewController, animated: true) } } // MARK: - Search Controller Functions extension MoviesViewController: UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate { func updateSearchResults(for searchController: UISearchController) { self.viewModel.updateSearchController(searchBarText: searchController.searchBar.text) } } 

Here is the screenshot ..

enter image description here

4
  • "Problem is not filtering the data" So what's the problem? I have seen the same topic or a similar one three or four times in the past several days. How is this topic different from previous ones? Commented Feb 19, 2024 at 11:21
  • Here I have design the search bar programmatically but the updateSearchResults function is not giving the appropriate result Commented Feb 19, 2024 at 11:24
  • 1
    @Nus updateSearchController check result here. print self.filteredMovie if it's getting right result just reload tableview below self.filteredMovie. Commented Feb 19, 2024 at 12:22
  • @OmSanatan that was the fixed need to reload the table view to update the view Commented Feb 19, 2024 at 12:40

0