HomeiOS Developmentios - SeachBar performance is just not working with UISearchController

ios – SeachBar performance is just not working with UISearchController


I’ve created the search bar programatically and I’m anticipating to filter the info when the textual content is enter into search bar. Drawback is just not filtering the info though I’ve information already downloaded kind api name and tried to look the textual content primarily based on the title.

Right here is the view mannequin code together with the search perform..

import Basis
import UIKit

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

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

ultimate class MoviesViewModel {

    non-public 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(Film.topRated) { [weak self] lead to
            change outcome {
            case .success(let web page):
                self?.state = .loaded(web page.outcomes)
            case .failure:
                self?.state = .error
            }
        }
    }
}

// MARK: - Search perform.
extension MoviesViewModel {
    
    public func inSearchMode(_ searchController: UISearchController) -> Bool {
        let isActive = searchController.isActive
        let searchText = searchController.searchBar.textual content ?? ""
        
        return isActive && !searchText.isEmpty
    }
    
    public func updateSearchController(searchBarText: String?) {
        self.filteredMovie = state.films

        if let searchText = searchBarText?.lowercased() {
            guard !searchText.isEmpty else { return }
            
            self.filteredMovie = self.filteredMovie.filter({ $0.title.lowercased().incorporates(searchText) })
        }
    }
}

Right here is the view controller code.

import UIKit

ultimate class MoviesViewController: UITableViewController {
    
    non-public let viewModel: MoviesViewModel
    // MARK: - UI Parts
    non-public let searchController = UISearchController(searchResultsController: nil)
    
    init(viewModel: MoviesViewModel) {
        self.viewModel = viewModel
        tremendous.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        title = LocalizedString(key: "films.title")

        NotificationCenter.default.addObserver(self, selector: #selector(textSizeChanged), title: UIContentSizeCategory.didChangeNotification, object: nil)

        setupSearchController()
        configureTableView()
        updateFromViewModel()
        bindViewModel()
        viewModel.fetchData()
    }

    non-public func configureTableView() {
        tableView.dm_registerClassWithDefaultIdentifier(cellClass: MovieCell.self)
        tableView.rowHeight = UITableView.automaticDimension

        refreshControl = UIRefreshControl()
        refreshControl?.addTarget(self, motion: #selector(refreshData), for: .valueChanged)
    }

    non-public func bindViewModel() {
        viewModel.updatedState = { [weak self] in
            guard let self else { return }
            DispatchQueue.major.async {
                self.updateFromViewModel()
            }
        }
    }

    non-public func updateFromViewModel() {
        change viewModel.state {
        case .loading, .loaded:
            tableView.reloadData()
        case .error:
            showError()
        }
        refreshControl?.endRefreshing()
    }

    // MARK: setUpSearch Property.
    non-public func setupSearchController() {
        
        self.searchController.searchResultsUpdater = self
        self.searchController.obscuresBackgroundDuringPresentation = false
        self.searchController.hidesNavigationBarDuringPresentation = false
        self.searchController.searchBar.placeholder = "Search Film"
        
        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.lower"), for: .bookmark, state: .regular)
    }
    
    non-public func showError() {
        let alertController = UIAlertController(title: "", message: LocalizedString(key: "films.load.error.physique"), preferredStyle: .alert)
        let alertAction = UIAlertAction(title: LocalizedString(key: "films.load.error.actionButton"), fashion: .default, handler: nil)
        alertController.addAction(alertAction)
        current(alertController, animated: true, completion: nil)
    }

    @objc non-public func refreshData() {
        viewModel.fetchData()
    }

    @objc non-public func textSizeChanged() {
        tableView.reloadData()
    }
}

// MARK: - UITableViewDataSource
extension MoviesViewController {

    override func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
        let inSearchMode = self.viewModel.inSearchMode(searchController)
        return inSearchMode ? self.viewModel.filteredMovie.depend : self.viewModel.state.films.depend   }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: MovieCell = tableView.dm_dequeueReusableCellWithDefaultIdentifier()

        let inSearchMode = self.viewModel.inSearchMode(searchController)
        
        let film = inSearchMode ? self.viewModel.filteredMovie[indexPath.row] : self.viewModel.state.films[indexPath.row]
        cell.configure(film)

        return cell
    }
}

// MARK: - UITableViewControllerDelegate
extension MoviesViewController {

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let film = viewModel.state.films[indexPath.row]
        let viewModel = MoviesDetailsViewModel(film: film, apiManager: APIManager())
        let viewController = MovieDetailsViewController(viewModel: viewModel)
        self.navigationController?.pushViewController(viewController, animated: true)
    }
}

// MARK: - Search Controller Capabilities
extension MoviesViewController: UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {
    
    func updateSearchResults(for searchController: UISearchController) {
        self.viewModel.updateSearchController(searchBarText: searchController.searchBar.textual content)
    }
}

Right here is the screenshot ..

enter image description here

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments