web-dev-qa-db-fra.com

Tentative de chargement de la vue d’un contrôleur de vue alors qu’il désalloue ... UISearchController

J'ai un code qui crée un UISearchController' in my UIVIew'sviewDidLoad`.

 self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.searchBar.delegate = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()
        controller.hidesNavigationBarDuringPresentation = false //prevent search bar from moving
        controller.searchBar.placeholder = "Search for song"

        self.myTableView.tableHeaderView = controller.searchBar

        return controller

    })()

Dès que cette fermeture est terminée, cet avertissement apparaît dans la console:

Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UISearchController: 0x154d39700>)

Je ne comprends pas ce que je fais mal. Cette question similaire n'est pas vraiment ma situation (du moins je ne le pense pas). Que se passe-t-il?

79
MortalMan

La vue de UISearchController doit être retirée de sa vue avant de désallouer. (devinez que c'est un bug) 

Objectif c...

-(void)dealloc { 
    [searchController.view removeFromSuperview]; // It works!
}

Swift 3 ...

deinit {
    self.searchController.view.removeFromSuperview()
}

Je me suis battu avec ce problème pendant quelques semaines. ^^

118
JJH

Résolu! C'était une solution simple. J'ai changé ce code

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

pour ça: 

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

Cela corrige le problème.

36
MortalMan

Voici la version de Swift qui a fonctionné pour moi (similaire à la réponse deJJH):

deinit{
    if let superView = resultSearchController.view.superview
    {
        superView.removeFromSuperview()
    }
}
20
nijm
class SampleClass: UITableViewController, UISearchBarDelegate {

private let searchController =  UISearchController(searchResultsController: nil)

 override func viewDidLoad() {
        super.viewDidLoad()

        searchController.loadViewIfNeeded() // Add this line before accessing searchController
 }

}
11
harsh_v

En combinant quelques solutions, j'ai réussi à faire fonctionner la mienne en ajoutant des lignes à viewDidLoad before en configurant entièrement UISearchController:

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationItem.rightBarButtonItem = self.editButtonItem()

    if #available(iOS 9.0, *) {
        self.resultSearchController.loadViewIfNeeded()// iOS 9
    } else {
        // Fallback on earlier versions
        let _ = self.resultSearchController.view          // iOS 8
    }
    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()

        self.tableView.tableHeaderView = controller.searchBar

        return controller
    })()

    self.tableView.reloadData()

}
10
Derek

Dans la version 2.2 de Swift qui a fonctionné pour moi

deinit {
    self.searchController?.view.removeFromSuperview()
}

Je pense que c'est utile!

7
Milos Mandic

Dans Swift2, j'ai reçu le même message d'erreur en raison d'un bogue évident:

let alertController = UIAlertController(title: "Oops",
    message:"bla.", preferredStyle: UIAlertControllerStyle.Alert)

alertController.addAction(UIAlertAction(title: "Ok", 
     style: UIAlertActionStyle.Default,handler: nil))

self.presentViewController(alertController, animated: true, completion: nil)

En raison d'une erreur de copie stupide de ma part, je n'avais pas inclus la ligne self.presentViewController. Cela a causé la même erreur.

7
Vincent

Le mien travaille comme ça

func initSearchControl(){

        searchController = UISearchController(searchResultsController: nil)

        if #available(iOS 9.0, *) {
            searchController.loadViewIfNeeded()
        } else {
            let _ = self.searchController.view
        }

        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true
        tableView.tableHeaderView = searchController.searchBar
        searchController.searchBar.sizeToFit()
    }

searchController.loadViewIfNeeded () résout le problème, mais vous devez l'appeler après l'initialisation de searchController.

2
mehmetsen80

La création d'un contrôleur de recherche dans viewDidLoad() et la définition de sa barre de recherche comme affichage du titre de l'élément de navigation ne créent pas une référence forte au contrôleur de recherche, c'est pourquoi il est désalloué.

Donc au lieu de faire ceci:

override func viewDidLoad() {
    super.viewDidLoad()
    // Create search controller
    let searchController = UISearchController(searchResultsController: nil)
    // Add search bar to navigation bar
    navigationItem.titleView = searchController.searchBar
    // Size search bar
    searchController.searchBar.sizeToFit()
}

Vous devriez faire ceci:

var searchController: UISearchController!

override func viewDidLoad() {
    super.viewDidLoad()
    // Create search controller
    searchController = UISearchController(searchResultsController: nil)
    // Add search bar to navigation bar
    navigationItem.titleView = searchController.searchBar
    // Size search bar
    searchController.searchBar.sizeToFit()
}
2
Niels

Ce n'est pas un bug. Il semble que vous deviez éviter de créer des ViewControllers sans les présenter. Donc, après SomeViewController() ou let variable: SomeViewController, vous devez appeler quelque chose comme ceci self.presentViewController(yourViewController ...etc). Si vous ne le faites pas, vous recevrez cet avertissement lorsque ce contrôleur de vue sera attribué.

1
Nikolai Ischuk

J'ai utilisé la réponse de Derek, mais je devais la modifier légèrement ... La réponse fournie m'écrasait, car l'appel à loadViewIfNeeded () s'était passé avant la définition de resultSearchController. (Ma déclaration était

var resultSearchController: UISearchController!

). Alors je l'ai juste déplacé après et cela a fonctionné.

Si je laissais complètement l'appel, le bogue demeurait, alors je suis sûr que c'est un élément essentiel de la réponse. Je n'ai pas pu le tester sur iOS 8.

1
Michael L. Mehr

Il semble que la vue soit chargée par défaut, si vous avez alloué le contrôleur et ne l'avez jamais affiché, la vue n'est pas chargée. Dans ce cas, si le contrôleur est désalloué, vous recevrez cet avertissement. vous pouvez l'afficher une fois ou appeler la méthode loadViewIfNeed () ou utiliser 'let _ = controller.view' pour forcer le chargement de la vue afin d'éviter cet avertissement.

1
david

Je suis un peu en retard à la fête, mais voici ma solution:

var resultSearchController: UISearchController!

override func viewDidLoad()
{
    super.viewDidLoad()

    self.resultSearchController = ({
        let searchController = UISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        searchController.searchBar.sizeToFit()
        return searchController
    })()

    self.tableView.tableHeaderView = self.resultSearchController.searchBar
    self.tableView.reloadData()
}

J'espère que cela fonctionne pour vous.

0
titusmagnus