Table view cell DidSelect function not navigating correct cell data

49 Views Asked by At

I have implement search functionality on table view and it working fine and able to filter the data. while data is filtering , the table view cell is update and reloaded correctly. When I done typing data into search bar and select the filtered cell , I am expecting to show selected filtered cell data into details view controller when the didSelectRowAt function is called. But it not showing the data from filtered cell , it showing different cell data.

Here is my view model code where I have search function.

// MARK: - Search function.

enum MoviesViewModelState {
    case loading
    case loaded([Movie])
    case error

    var movies: [Movie] {
        switch self {
        case .loaded(let movies):
            return movies
        case .loading, .error:
            return []
        }
    }
}

/// Calling API for movie data. here 
final class MoviesViewModel {

/// API call is happening here. 
}
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 table view controller code ..

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")

        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.tintColor = .purple
        searchController.searchBar.setImage(UIImage(named: "Filter"), for: .bookmark, state: .normal)
        searchController.searchBar.setLeftImage(UIImage(named: "Search"))
        searchController.searchBar.showsBookmarkButton = true

    }

    @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)
        tableView.reloadData()
    }
}

Here is the screenshot of the filtering data.. when I select the first filtered cell (the Godfather) , I am expecting to show the details of that cell into details view controller.

[filtering data (https://i.stack.imgur.com/blEZ4.png)

But here is the result when I select the filtered cell and it showing the wrong data into details view controller.

detils view controller view

0

There are 0 best solutions below