Activating a search controller whose navigation item is not at the top of the stack | Swift

54 views Asked by At

The error: [Assert] Surprise! Activating a search controller whose navigation item is not at the top of the stack. This case needs examination in UIKit. items = (null), search hosting item = <UINavigationItem: 0x1068473a0> title='PARTS' style=navigator leftBarButtonItems=0x282bfb8d0 rightBarButtonItems=0x282bfb890 searchController=0x110024400 hidesSearchBarWhenScrolling

Why am I getting this error and how do I fix it? This question is similar to another post, but there was only one response to it and the response was not detailed at all (therefore not helpful).

import UIKit
import SPStorkController

struct Part {
    var title: String?
    var location: String?
    var selected: Bool? = false
}

class InspectorViewController: UIViewController, UINavigationControllerDelegate, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating, UISearchBarDelegate {
    
    private let initials = InspectorPartsList.getInitials() // model
    private var parts = InspectorPartsList.getDamageUnrelatedParts() // model
    var filteredParts: [Part] = [] // model
    var searching = false
    
    var searchController = UISearchController(searchResultsController: nil)
    lazy var searchBar: UISearchBar = UISearchBar()
    var isSearchBarEmpty: Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }
    
    var navBar = UINavigationBar()
    
    let inspectorTableView = UITableView() // tableView
    var darkTheme = Bool()

    override func viewDidLoad() {
        super.viewDidLoad()
        // setup the navigation bar
        setupNavBar()
        
        // add the table view
        setupInspectorTableView()
        
        // add the search controller to the navigation bar
        setupSearchController()
    }
    
    func setupNavBar() {
        navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 100))
        view.addSubview(navBar)
        let navItem = UINavigationItem(title: "PARTS")
        let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(self.addBtnTapped))
        let cancelItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: nil, action: #selector(self.cancelBtnTapped))
        navItem.rightBarButtonItem = doneItem
        navItem.leftBarButtonItem = cancelItem
        navItem.searchController = searchController
        navBar.setItems([navItem], animated: false)
    }
    
    @objc func cancelBtnTapped() {
        // dismiss the storkView
        SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
    }
    
    @objc func addBtnTapped() {
        // get all of the selected rows
        // Update the InspectionData model with the selected items... this will allow us to update the InspectionTableView in the other view
        
        // create an empty array for the selected parts
        var selectedParts = [Part]()
        
        // loop through every selected index and append it to the selectedParts array
        for part in parts {
            if part.selected! {
                selectedParts.append(part)
            }
        }
        
        // update the InspectionData model
        if !selectedParts.isEmpty { // not empty
            InspectionData.sharedInstance.partsData?.append(contentsOf: selectedParts)
            // update the inspectionTableView
            updateInspectionTableView()
        }
        
        // dismiss the storkView
        SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
    }
    
    func cancelAddPart() {
        // dismiss the storkView
        SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
    }
    
    private func setupInspectorTableView() {
        // set the data source
        inspectorTableView.dataSource = self
        
        // set the delegate
        inspectorTableView.delegate = self
        
        // add tableview to main view
        view.addSubview(inspectorTableView)
        
        // set constraints for tableview
        inspectorTableView.translatesAutoresizingMaskIntoConstraints = false
//        inspectorTableView.topAnchor.constraint(equalTo: fakeNavBar.bottomAnchor).isActive = true
        inspectorTableView.topAnchor.constraint(equalTo: navBar.bottomAnchor).isActive = true
        inspectorTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        inspectorTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        inspectorTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        
        // allow multiple selection
        inspectorTableView.allowsMultipleSelection = true
        inspectorTableView.allowsMultipleSelectionDuringEditing = true
        
        // register the inspectorCell
        inspectorTableView.register(CheckableTableViewCell.self, forCellReuseIdentifier: "inspectorCell")
    }
    
    func setupSearchController() {
        // add the bar
        searchController.searchResultsUpdater = self
        searchController.searchBar.delegate = self
        searchController.hidesNavigationBarDuringPresentation = false
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "Search by part name or location"
        definesPresentationContext = true
        searchController.searchBar.sizeToFit()
        self.inspectorTableView.reloadData()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if searching {
            return filteredParts.count
        } else {
            return parts.count
        }
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let inspectorCell = tableView.dequeueReusableCell(withIdentifier: "inspectorCell", for: indexPath)
        var content = inspectorCell.defaultContentConfiguration()
        var part = Part()
        
        if searching {
            // showing the filteredParts array
            part = filteredParts[indexPath.row]
            if filteredParts[indexPath.row].selected! {
                // selected - show checkmark
                inspectorCell.accessoryType = .checkmark
            } else {
                // not selected
                inspectorCell.accessoryType = .none
            }
        } else {
            // showing the parts array
            part = parts[indexPath.row]
            if part.selected! {
                // cell selected - show checkmark
                inspectorCell.accessoryType = .checkmark
            } else {
                // not selected
                inspectorCell.accessoryType = .none
            }
        }
        
        content.text = part.title
        content.secondaryText = part.location
        inspectorCell.contentConfiguration = content
        
        return inspectorCell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // Note: When you select or unselect a part in the filteredParts array, you must also do so in the parts array
        if searching { // using filteredParts array
            if filteredParts[indexPath.row].selected! { // selected
                filteredParts[indexPath.row].selected = false // unselect the part
                // search the parts array for the part by both the title and location, so we for sure get the correct part (there could be parts with identical titles with different locations)
                if let part = parts.enumerated().first(where: { $0.element.title == filteredParts[indexPath.row].title && $0.element.location == filteredParts[indexPath.row].location}) { // exact part (with same title & location) found
                    parts[part.offset].selected = false // unselect the part
                }
            } else { // not selected
                filteredParts[indexPath.row].selected = true // select the part
                if let part = parts.enumerated().first(where: { $0.element.title == filteredParts[indexPath.row].title && $0.element.location == filteredParts[indexPath.row].location}) { // exact part (with same title & location) found
                    parts[part.offset].selected = true // select the part
                }
            }
        } else { // using parts array
            if parts[indexPath.row].selected! { // selected
                parts[indexPath.row].selected = false // unselect the part
            } else { // not selected
                parts[indexPath.row].selected = true // select the part
            }
        }
        inspectorTableView.reloadRows(at: [indexPath], with: .none) // reload the tableView
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        filteredParts = parts.filter { ($0.title?.lowercased().prefix(searchText.count))! == searchText.lowercased() }
        searching = true
        inspectorTableView.reloadData()
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searching = false
        searchBar.text = ""
        inspectorTableView.reloadData()
    }
    
    func updateSearchResults(for searchController: UISearchController) {
    }
    
    private func updateInspectionTableView() {
        NotificationCenter.default.post(name: NSNotification.Name("updateInspectionTable"), object: nil)
    }

}

// CHECKABLE UITABLEVIEWCELL
class CheckableTableViewCell: UITableViewCell {
}
0

There are 0 answers