Versuch, die Ansicht eines Ansichtscontrollers zu laden, während die Zuordnung aufgehoben wird ... UISearchController

80

Ich habe Code, der eine UISearchController' in my UIVIew'sviewDidLoad` erstellt.

 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

    })()

Unmittelbar nach Abschluss dieser Schließung wird diese Warnung in der Konsole angezeigt:

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

Ich verstehe nicht, was ich falsch mache. Diese ähnliche Frage ist nicht wirklich meine Situation (zumindest glaube ich das nicht). Was ist los?

MortalMan
quelle
xkcd.com/583 Funktioniert einwandfrei, wenn ich das in meine Tabelle VC werfe viewDidLoad(). Empfehlen Sie a) die vollständige VC-Quellenliste einzuschließen und b) sicherzustellen, dass der Fehler tatsächlich dort auftritt, wo und wann Sie glauben, dass er vorliegt.
BaseZen
Machen Sie auch weitere Nachforschungen wie: stackoverflow.com/questions/31006045/…, das den gleichen Fehler aufweist
BaseZen
Also habe ich ein schnelles Projekt gemacht, alles progressiv gemacht, keine Storyboards, und ich habe kein Problem. Ist dies ein Storyboard-Problem, das Sie vielleicht haben, ich weiß es nicht, aber ich gehe davon aus, dass Sie Storyboards verwenden, oder? Wenn ich programmatisch sage, meine ich keine Schreibfedern, keine Storyboards, alles Code und es funktioniert gut
Loxx
@BaseZen Ich habe vorher })()und nachher einen Haltepunkt gesetzt })(). Der Fehler wird ausgelöst, nachdem der Abschluss beendet ist. Ich habe eine UIViewController, keine tableViewController.
MortalMan
@Larcerax Ich habe ein Storyboard. Es enthält nur einen Navigations-Controller und einen UIViewController (sie sind verbunden.)
MortalMan

Antworten:

118

Die Ansicht von UISearchController muss vor der Freigabe aus der Übersicht entfernt werden. (denke, es ist ein Fehler)

Ziel c...

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

Swift 3 ...

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

Ich hatte ein paar Wochen mit diesem Problem zu kämpfen. ^^

JJH
quelle
1
Das ist wirklich komisch ... Aber es hat auch für mich den Trick getan. Ich denke, es ist in der Tat ein Fehler.
Mihai Fratu
22
Ich hatte das gleiche Problem mit einem, dem UISearchControlerich zugeteilt hatte -viewDidLoad. Es ist definitiv ein Fehler - wenn die UISearchControllerZuordnung aufgehoben wird, bevor die Ansicht geladen wird, wird diese Warnung angezeigt. Wenn ich auf das Suchfeld tippe (wodurch die Ansicht geladen wird), wird es nicht angezeigt. Also in meinem deallocrufe ich an [self.searchController loadViewIfNeeded](neu in iOS 9),
Leehro
4
@ Leehros Kommentar ist die Antwort für mich. es kam heraus alsif #available(iOS 9.0, *) { self.searchController?.loadViewIfNeeded() }
Tim
6
Ich möchte @ Leehros Kommentar hinzufügen, dass dies im Dealloc nicht erforderlich ist. Sie können stattdessen loadViewIfNeeded in viewDidLoad ausführen.
Clafou
Dank @Leehro und @Clafou ... ist das Hinzufügen des Anrufs [self.searchController loadViewIfNeeded];(Obj-C) die Antwort, die das Problem in meinem Code gelöst hat.
Andrew Builder
36

Gelöst! Es war eine einfache Lösung. Ich habe diesen Code geändert

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

dazu:

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

Dies behebt das Problem.

MortalMan
quelle
1
Ich habe es in das geändert, was du meintest. :-) Aus diesem Grund ist es besser, die gesamte Quelle in die Frage aufzunehmen, aber es ist am besten, sie selbst zu finden
;-)
Ich hatte auch diese nervige Warnung und nach Ihrer Antwort habe ich alles repariert. Aber ich weiß nicht warum die! wird benötigt, anstatt einen neuen UISearchController zuzuweisen ... würden Sie mich erklären?
SagittariusA
Ich bin mir nicht sicher, ich hätte auch gerne eine Erklärung.
MortalMan
Wenn ich von var resultSearchController = UISearchController () zu var resultSearchController wechsle: UISearchController! Ich erhalte einen schwerwiegenden Fehler: Beim Auspacken eines optionalen Werts in noOfRowInSection wurde unerwartet nil gefunden. Ich habe eine große Anzahl von Arrays. Ist das ein Fehler? Schlag mich vor.
Pawriwes
Ich fand heraus, anstatt Delegate und Datenquelle aus dem Storyboard zu erstellen, schrieb ich in den Code und das Problem wurde gelöst.
Pawriwes
20

Hier ist die Swift-Version, die für mich funktioniert hat (ähnlich der Antwort von JJH):

deinit{
    if let superView = resultSearchController.view.superview
    {
        superView.removeFromSuperview()
    }
}
nijm
quelle
@alex Ich habe es am Ende des View Controllers eingefügt, der den resultSearchController initialisiert.
Nijm
2
Sie brauchen das nicht wirklich, if letda .removeFromSuperView()es nichts tun wird, wennsuperview == nil
NSGangster
11
class SampleClass: UITableViewController, UISearchBarDelegate {

private let searchController =  UISearchController(searchResultsController: nil)

 override func viewDidLoad() {
        super.viewDidLoad()

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

}
hart_v
quelle
10

Ein paar Lösungen zusammenhacken Ich habe es geschafft, meine zum Laufen zu bringen, indem ich Zeilen zu viewDidLoad hinzugefügt habe, bevor ich den UISearchController vollständig eingerichtet habe:

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

}
Derek
quelle
Ich habe auch versucht jede andere Lösung , die hier gegeben, und keiner tat Unterdrückungs die Warnung (obwohl die Suchsteuerung tut zur Laufzeit arbeiten); das hat es geschafft. Vielen Dank!
Nicolas Miari
Dies hat mir auch geholfen, aber ich musste diese Zeile hinzufügen, nachdem ich UISearchController initialisiert hatte. self.searchController = ({ let controller = UISearchController(searchResultsController: nil) controller.searchResultsUpdater = self controller.dimsBackgroundDuringPresentation = false controller.searchBar.delegate = self definesPresentationContext = true controller.searchBar.sizeToFit() return controller })() dann self.searchController.loadViewIfNeeded()
yuzer
Warum müssen wir im Block initialisieren?
Code4latte
7

In Swift2 wurde aufgrund eines offensichtlichen Fehlers dieselbe Fehlermeldung angezeigt:

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)

Aufgrund eines dummen Kopierfehlers von mir selbst hatte ich die Zeile self.presentViewController nicht eingefügt. Dies verursachte den gleichen Fehler.

Vincent
quelle
7

In der Swift 2.2-Version hat das bei mir funktioniert

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

Ich finde es hilfreich!

Milos Mandic
quelle
2

Es ist kein Fehler. Es scheint, dass Sie vermeiden müssen, ViewController zu erstellen, ohne sie zu präsentieren. Also danach SomeViewController()oder let variable: SomeViewControllerdu musst so etwas anrufen self.presentViewController(yourViewController ...etc). Wenn Sie dies nicht tun, erhalten Sie diese Warnung, wenn dieser View Controller freigegeben wird.

Nikolai Ischuk
quelle
2

Meins funktioniert so

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 () löst das Problem, aber Sie müssen es nach der Initialisierung des searchController aufrufen

mehmetsen80
quelle
2

Wenn Sie einen Suchcontroller in viewDidLoad()erstellen und seine Suchleiste als Titelansicht des Navigationselements festlegen, wird kein starker Verweis auf den Suchcontroller erstellt, weshalb die Zuordnung aufgehoben wird.

Also anstatt dies zu tun:

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()
}

Du solltest das tun:

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()
}
Niels
quelle
1

Ich habe Dereks Antwort verwendet, musste sie aber leicht ändern. Die bereitgestellte Antwort stürzte für mich ab, da der Aufruf von loadViewIfNeeded () erfolgte, bevor der resultSearchController definiert wurde. (Meine Erklärung war

var resultSearchController: UISearchController!

). Also habe ich es einfach danach verschoben und es hat funktioniert.

Wenn ich den Anruf ganz ausgelassen habe, ist der Fehler geblieben, daher bin ich mir sicher, dass er ein wesentlicher Bestandteil der Antwort ist. Ich konnte es unter iOS 8 nicht testen.

Michael L. Mehr
quelle
1

Es scheint, dass die Ansicht verzögert geladen ist. Wenn Sie den Controller zugewiesen haben und ihn nie anzeigen, wird die Ansicht nicht geladen. In diesem Fall erhalten Sie diese Warnung, wenn der Controller freigegeben wird. Sie können es einmal anzeigen oder die Methode loadViewIfNeed () aufrufen oder mit 'let _ = controller.view' das Laden der Ansicht erzwingen, um diese Warnung zu vermeiden.

David
quelle
Unter iOS 8 können Sie nur 'let _ = controller.view' verwenden.
David
0

Ich bin etwas spät zur Party, aber hier ist meine Lösung:

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()
}

Ich hoffe es funktioniert bei dir.

Titusmagnus
quelle
Wie unterscheidet sich dies von der direkten Initialisierung und Einrichtung? Ich meine ohne die Blocksyntax zu verwenden?
Code4latte