IBOutlet ist null, aber es ist im Storyboard Swift verbunden


102

Verwenden von Swift 1.1 und Xcode 6.2.

Ich habe ein UIStoryboard mit einer einzelnen benutzerdefinierten UIViewControllerUnterklasse. Darauf habe ich eine @IBOutletVerbindung vom Typ UIViewvon diesem Controller zu einer UIView Unterklasse im Storyboard. Ich habe auch ähnliche Verkaufsstellen für Unteransichten dieser Ansicht. Siehe Abbildung A.

Zur Laufzeit sind diese Eigenschaften jedoch gleich Null (Abbildung B). Obwohl ich versichert habe, dass ich die Steckdosen in Interface Builder angeschlossen habe.

Gedanken :

  • Ist es möglich, dass etwas die Initialisierung durcheinander bringt, weil ich eine Unterklasse einer Unterklasse verwende? Ich überschreibe keine Initialisierer
  • awakeFromNib: wird aus irgendeinem Grund nicht angerufen
  • Möglicherweise wird keine Verbindung zu Unteransichten in Unteransichten hergestellt

Dinge, die ich versucht habe:

  • @IBOutletGenau passende und Storyboard-Elementtypen (anstelle vonUIView )
  • Löschen von Eigentum und Steckdose und erneutes Hinzufügen

Abbildung A.

Abbildung A *

Abbildung B.

Abbildung B.

* Der verdeckte Code in Figure Aist:

@IBOutlet private var annotationOptionsView: UIView!
@IBOutlet private var arrivingLeavingSwitch: UISegmentedControl!

Danke dir.


Warum nicht das ändern! zu?

clearView ist null, da es nicht mit dem Storyboard verknüpft ist (siehe den Kreis links im Code mit einem Loch, das angibt, dass es nicht verknüpft ist). Im Screenshot kann ich die Deklaration von annotationOptionView nicht sehen.
Javier Flores Font

@ JavierFloresFont: clearViewIch erwarte, Null zu sein. Es ist etwas, das ich noch nicht umgestaltet habe. Siehe auch die Fußnote zu Abbildung A. @ShaanSingh Es sollte sein! weil Verbindungen von Storyboards zur Laufzeit festgelegt werden (sollen) und nicht Null sein sollten.
Stefan Arambasich

Wie wird dieser View Controller geladen? Zeigen Sie uns den Code, der danach fragt, oder beschreiben Sie den Abschnitt, der mit ihm verbunden ist.
Rob Mayoff

1
Es bekommt das richtige Storyboard: let vc = UIStoryboard(name: "LocationPickerModal", bundle: nil) .instantiateViewControllerWithIdentifier("LocationPickerModalViewController") as LocationPickerModalViewController
Stefan Arambasich

Antworten:


146

Dies geschieht normalerweise, weil Ihr Ansichts-Controller seine Ansichtshierarchie noch nicht geladen hat. Ein Ansichts-Controller lädt seine Ansichtshierarchie nur, wenn ihm etwas die viewNachricht sendet . Das System tut dies, wenn es Zeit ist, die Ansichtshierarchie tatsächlich auf dem Bildschirm anzuzeigen, was geschieht, nachdem Dinge wie prepareForSegue:sender:und viewWillAppear:zurückgekehrt sind.

Da Ihr VC seine Ansichtshierarchie noch nicht geladen hat, sind Ihre Outlets immer noch gleich Null.

Sie können den VC zwingen, seine Ansichtshierarchie zu laden, indem Sie sagen _ = self.view.


4
Dies geschieht, wenn viewWillAppear:aufgerufen wird, wenn ich zum ersten Mal etwas mit dieser Steckdose mache. Der Zugriff auf die Ansicht bringt mir nichts. Immer noch null.
Stefan Arambasich

Vielen Dank! Das hat auch bei mir funktioniert. var v = viewcontroller.view; gezwungen, die Ansichtshierarchie zu laden. Schöner kleiner Trick! ;)
Yordi Uytersprot

@YordiUytersprot wo würdest du diese Zeile setzen?
Async

4
Wenn Sie einen Viewcontroller instanziieren: Lassen Sie vc = self.storyboard? .InstantianteViewControllerWithIdentifier ("StoryboardIDfromVC") als? CustomVC; let view = vc.view; // Im Moment können Sie hier von CustomVC aus auf IBOutlets zugreifen. Vc.customTextField.text = "Lalala"; Hoffe es hilft dir! :)
Yordi Uytersprot

4
UIViewcontroller.loadViewIfNeeded()ist die richtige Methode, um hier zu verwenden.
Orkoden

27

Haben Sie versucht, Produkt> Reinigen auszuführen? Ein sehr ähnliches Problem für mich gelöst.


Ich tat. Entschuldigung, soll meine Antwort markieren. Es begann erst zu funktionieren, nachdem ich den DerivedDataOrdner für das Projekt gelöscht hatte .
Stefan Arambasich

3
Nur zwei meiner Filialen in der Mitte meiner Ansichtshierarchie waren gleich Null. Produkt -> Sauber hat bei mir funktioniert!
Rikco

1
obj c, nur das Projekt zu reinigen hat bei mir funktioniert ... kann nicht glauben, dass ich mehr als eine Stunde verbracht habe und nicht einmal daran gedacht habe, das Projekt zu reinigen: / aber danke !!
Gewächshaus

Nur Produkt -> Reinigen hat bei mir nicht funktioniert, aber ich habe einen anderen Simulator gestartet und es hat funktioniert, daher muss auch im Ordner DerivedData etwas nicht stimmen.
Endavid

22

Haben Sie Ihren View Controller über ein Storyboard oder eine NIB instanziiert oder direkt über einen Initialisierer instanziiert?

Wenn Sie Ihre Klasse direkt mit dem Initialisierer instanziiert haben, werden die Steckdosen nicht verbunden. Der Interface Builder erstellt benutzerdefinierte Instanzen Ihrer Klassen und codiert diese Instanzen zur wiederholten Dekodierung in NIBs und Storyboards. Die Klassen selbst werden nicht definiert. Wenn dies Ihr Problem war, müssen Sie nur den Code ändern, in dem Sie Ihren Controller erstellen, um stattdessen die Methoden auf UIStoryboard oder UINib zu verwenden.


2
Ich erstelle eine UIStoryboardInstanz und rufe instantiateViewControllerWithIdentifiersie auf.
Stefan Arambasich

15

Das Storyboard erkannte keine weiteren UI-Dinge, die ich hinzugefügt hatte. Zur Laufzeit waren alle Referenzen gleich Null. Also habe ich meinen abgeleiteten Datenordner gelöscht und dann haben diese Verbindungen wieder funktioniert.


2
Das ist die Antwort. Ich habe eine ganze Weile dagegen gekämpft und den Build-Ordner und alles gereinigt. In meinem Fall wurden in viewDidLoad()allen Fällen Verbindungen hergestellt, in viewWillAppear()fast allen jedoch nil(manchmal waren noch ein oder zwei verbunden). Ich habe alles versucht und schließlich den abgeleiteten Datenordner gelöscht, neu erstellt und alles war gut.
Ruttopia

6
Selbst nach 3 Jahren hat Xcode 9.2 immer noch den gleichen verdammten Fehler. Ich danke dir sehr.
Kemal Can Kaynak

1
Hier, um zu berichten, dass dies in Xcode 11 noch vorhanden ist. :(
verbrachte den

13

Dies geschah mir mit meiner benutzerdefinierten Sammlungsansichtszelle. Es stellte sich heraus, dass ich meine registerClassforReuseIdentifier-Methode durch registerNib ersetzen musste. Das hat es für mich behoben.


Du hast recht. Ich habe den ARC-Zählinhalt in Swift Programming Language ausführlich gelesen. Ich kann den Grund nicht finden, warum die schwache IBOutlet-Eigenschaft immer noch Null ist. Endlich google ich nach '@IBOutlet swift nil' und finde deine Antwort in SO. Dann habe ich die Zeile Xcode-Vorlage markiert, die in viewDidLoad 'self.collectionView! .RegisterClass' hinzugefügt wurde. Dann funktioniert es. Du rettest mein Leben.
charles.cc.hsu

12

Dies geschah für mich, weil ich versehentlich meinen View Controller direkt instanziiert habe, anstatt ihn über das Storyboard zu instanziieren. Wenn Sie direkt über instanziieren, werden MyViewController()die Steckdosen nicht angeschlossen.


Wenn Sie eine XIB-Datei verwenden, funktioniert die direkte Instanziierung immer noch erfolgreich.
Luat Vu Dinh

11

In meinem Fall ist dies passiert, weil ich die loadViewMethode in meiner ViewController-Unterklasse überschrieben, aber vergessen habe, sie hinzuzufügen[super loadView]

-(void)loadView {
// blank
}

Wenn Sie die überschreiben loadView Methode , liegt es in Ihrer Verantwortung, Ihre Unteransichten zu initiieren. Da Sie es überschreiben, können die Ansichten des Interface Builder nicht in Kakaoobjekte konvertiert werden, sodass die Ausgänge gleich Null bleiben.

Wenn Sie loadView in Ihrer View Controller-Unterklasse implementieren, liegt es in Ihrer Verantwortung, die UI-Elemente aus Storyboard / xib in Code zu laden.

Oder einfach anrufen

[super loadView];

Damit die Superklasse die Möglichkeit bekommt, Storyboard / xib in Code zu laden.


8

Sie können controller.viewerzwingen, um das Laden der Ansicht zum Initialisieren der IBOutlets zu erzwingen. Anschließend können Sie die Werte zuweisen.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "identifier") {
        let controller = segue.destinationViewController as! YourController
        let _ = controller.view //force to load the view to initialize the IBOutlets

        controller.your_IBOutlet_property = xxx
        ...
        controller.delegate = self
    }
}

7

Wenn Sie view controllerprogrammgesteuert durch instanziieren . Versuchen Sie dann, es wie unten zu erstellen

let initialVC = self.storyboard?.instantiateViewController(withIdentifier: "InitialVC") as! InitialVC

statt direkt

let initialVC = InitialVC()

Das hat bei mir funktioniert.


6

Für mich trat dies auf, als ich versehentlich die Klasse meines View Controllers als deklarierte

class XYZViewController: UINavigationController {
}

(dh als UINavigationControllernicht aUIViewController ).

Xcode nicht abholen auf diesem Fehler auf, die Klasse zu bauen fein scheint, und überschreiben Funktionen wie viewDidLoad, viewWillAppearusw. alle korrekt funktionieren. Aber keiner von denIBOutlet s wird verbunden.

Ändern der Deklaration in

class XYZViewController: UIViewController {
}

reparierte es vollständig.


5

Ich bin kürzlich auf dieses Problem gestoßen! Hier ist mein Gedanke. Das Problem betrifft nicht Ihr Storyboard oder ein Linkproblem. Es geht darum, wie Sie Ihren ViewController initiieren. Besonders wenn Sie Swift verwenden. (Beim Erstellen einer Klassendatei befindet sich kaum etwas im Editor.)

Durch die einfache Verwendung der init()from super class kann nichts initiiert werden, was Sie mit Storyboard gearbeitet haben. Sie müssen also die Initialisierung des ViewControllers ändern. Ersetzen let XXViewController = XXViewController() durch let XXViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("XXViewController") as! XXViewController Dies weist das Programm an, zum Storyboard zu gehen, um XXViewController zu finden, und initiiert alles IBOutletin Ihrem Storyboard.

Hoffe diese Hilfe ~ GL


Das war nicht das Problem
Stefan Arambasich

4

2019, EINE MÖGLICHKEIT FÜR DIESES SCHRECKLICHE PROBLEM:

  • Angenommen, Sie haben möglicherweise eine Containeransicht, die eine Art Uhr anzeigt. Also hast du

    Klassenuhr: UIViewController

Sie verwenden es tatsächlich an mehreren Stellen in der App .

Auf dem Hauptbildschirm, auf dem Detailbildschirm, auf dem Bearbeitungsbildschirm.

Sie haben eine komplizierte Snapchat-ähnliche moderne App.

In der Tat Clockwerden kann tatsächlich geladen mehr als einmal in der gleichen Zeit irgendwo auf dem gleichen Bildschirm . (Vielleicht ist es in einigen Fällen versteckt.)

Sie beginnen mit der Arbeit an einer Instanz Clockeines Ihrer vielen Storyboards.

Auf diesem Storyboard fügen Sie ein Label hinzu, NewLabel.

Natürlich fügen Sie die Steckdose im Code hinzu. Alles sollte funktionieren. Alle anderen Steckdosen funktionieren einwandfrei.

Sie haben die Steckdose definitiv verbunden.

Aber die App stürzt mit NewLabel als Null ab.

Xcode sagt Ihnen deutlich, dass Sie vergessen haben, die Steckdose anzuschließen.

Der Grund dafür ist, dass Sie "NewLabel" nur für eine der Storyboard-Anwendungen von Clock haben!

Der Absturz ist tatsächlich von >>> einem anderen Ort <<<<, an dem Sie Clock verwenden !!!!

Xcode sagt Ihnen nicht , dass der Absturz von einem anderen Ort stammt, nicht von Ihrem Arbeitsplatz aus!

Der Absturz ist eigentlich nicht von dem Ort, an dem Sie arbeiten - es ist von einem anderen Storyboard, wo sich kein "NewLabel" -Element auf diesem Storyboard befindet !!!

Frustrierend.


3

Für Swift 3.

func configureView() {
    let _  = self.view
}

2

Sie müssen zuerst die Ansichtshierarchie laden, um die Ausgänge im Storyboard zu instanziieren. Dazu können Sie die Methoden loadView oder loadViewIfNeeded manuell aufrufen.


2

In meinem Fall stürzte die App plötzlich ab. Das Debuggen ergab, dass sich alle Verkaufsstellen nilzum Zeitpunkt von noch befanden viewDidLoad().

Meine App verwendet immer noch Schreibfedern für die meisten View-Controller (keine Storyboards). Alles war vorhanden, alle Steckdosen richtig verdrahtet. Ich habe es noch einmal überprüft.

Wir instanziieren unsere View Controller normalerweise als

let newVC = MYCustomViewController()

... was aus irgendeinem Grund zu funktionieren scheint, solange die .xib den gleichen Namen wie die View-Controller-Klasse hat (ich bin mir jedoch nicht sicher, wie das funktioniert. Wir rufen nichtinit(nibName:bundle:) mit null Argumenten auf oder überschreiben dies init(), um es so weiter zu selfmachen wird normalerweise vorgeschlagen ...).

Also habe ich versucht explizit anzurufen

 let newVC = MYCustomViewController(nibName: "MYCustomViewController", bundle: .main)

... nur um mit dem Laufzeitausnahmefehler begrüßt zu werden:

*** Beenden der App aufgrund der nicht erfassten Ausnahme 'NSInternalInconsistencyException', Grund: 'NIB konnte nicht im Bundle geladen werden:' NSBundle </ Users / nicolasmiari / Library / Developer / CoreSimulator / Devices / 3DA3CF21-108D-498F-9649-C4FC9E3C1A8D / data /Containers/Bundle/Application/C543DDC1-AE86-4D29-988C-9CCE89E23543/MyApp.app> (geladen) 'mit dem Namen' MYCustomViewController ''

Und dann habe ich es gesehen:

Das Kontrollkästchen "Zielmitgliedschaft" der .xib-Datei wurde deaktiviert.


Muss bei der Lösung eines der häufigen Zusammenführungskonflikte in Bezug auf die Xcode-Projektdatei aufgetreten sein.

Apple muss auf jeden Fall ein Projektdateiformat entwickeln, das SCM-freundlicher ist.


2

100% funktionierende Lösung zum Erstellen von ViewControllern aus XIB ohne StoryBoards

  1. Klasse CustomViewController erstellen: UIViewController
  2. Erstellen Sie die Ansicht CustomViewControllerView.xib
  3. Wählen Sie in CustomViewControllerView.xib im Interface Builder Platzhalter -> Dateibesitzer aus
  4. Setzen Sie im "Attributes Inspector" die Klasse auf CustomViewController
  5. Verbinden Sie im "Verbindungsinspektor" die "Ansicht" mit der Ansicht von xib auf oberster Ebene (stellen Sie sicher, dass die Klasse der Ansicht auf oberster Ebene nicht auf CustomViewController zeigt).
  6. Schließen Sie im "Verbindungsinspektor" andere Steckdosen an (falls erforderlich / vorhanden).
  7. Erstellen Sie eine Instanz von CustomViewController im übergeordneten View Controller / App-Delegaten

7.1.

// creating instance
let controller = CustomViewController()

7.2.

// connecting view/xib with controller instance
let bundle = Bundle(for: type(of: controller))
bundle.loadNibNamed("CustomViewControllerView", owner: controller, options: nil)

7.3.

// get/set outlets
controller.labelOutlet.text = "title"
controller.imageOutlet.image = UIImage(named: "image1")

Fantastische Antwort, danke! Sie können init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)Schritt 7.2 auch selfdirekt in der CustomViewController-Klasse überschreiben und aufrufen .
Brandonscript

1

Überprüfen Sie Ihre IBOutlet-Verbindung, wenn sie mit dem Dateieigentümer oder der Ansicht verbunden ist. Es könnte Fehler geben.


1

Anderer Fall:

Ihre Steckdosen werden erst festgelegt, wenn die Ansicht des View Controllers tatsächlich instanziiert wurde. Dies geschieht in Ihrem Fall wahrscheinlich kurz nach initWithNibName: bundle: - zu diesem Zeitpunkt sind sie noch gleich Null. Alle Einstellungen, die Sie an diesen Ausgängen vornehmen, sollten in der -viewDidLoad-Methode Ihres View Controllers erfolgen.


1

Ich hatte den gleichen Fehler in einem lokalisierten Storyboard, ein Element wurde in einem Gebietsschema hinzugefügt und nicht in dem anderen. Daher hatte ich beim Umschalten auf das Gebietsschema für fehlende Elemente eine Nullreferenz für dieses Element, für die ich die (redundante) Lokalisierung entfernen musste das Storyboard unter https://stackoverflow.com/a/42256341/1356559 .


1

Für mich stürzte das ab, weil containerViewes gleich Null war.

Hier ist mein Code mit Crash .

@IBOutlet private var containerView: UIView!  // Connected to Storyboard
override open func loadView() {
    containerView.addSubview(anotherView)
}

Das fehlende Ding rief das an super.loadView(). Das Hinzufügen löste das Problem für mich.

Fester Code :

@IBOutlet private var containerView: UIView!
override open func loadView() {
    super.loadView()
    containerView.addSubview(anotherView)
}

Sie sollten loadView () niemals direkt aufrufen ( developer.apple.com/documentation/uikit/uiviewcontroller/… ), sondern stattdessen self.view aufrufen
Lio

1

Ich hatte ein ähnliches Problem, als ich zuvor das Register (_: forCellReuseIdentifier :) für die benutzerdefinierte Zelle hinzugefügt hatte, nachdem ich den Bezeichner bereits im Storyboard definiert hatte. Hatte diesen Code in der viewDidLoad () Funktion. Sobald ich es entfernt habe, hat es gut funktioniert.


1

Ein weiterer Fall, auf den ich gerade gestoßen bin. Ich habe den Namen meiner Klasse für den UIViewController geändert, aber vergessen, den Namen der .xib-Datei zu ändern, in der die Schnittstelle erstellt wurde.

Nachdem ich das verstanden und die Dateinamen den Klassennamen wiedergegeben hatte, war alles gut!

Ich hoffe das hilft jemandem.


1

Habe noch einen ...

Wenn Sie eine benutzerdefinierte Klasse für eine UITableViewCell haben, aber vergessen, Custom im Stil der Zelle anzugeben.


1

Sie können überprüfen, ob die is-Ansicht geladen ist.

if isViewLoaded && view.window != nil {
 //self.annotationOptionsView.
}

0
  1. Wählen Sie beide aus .hund zeigen Sie die .mController-Dateien an
  2. Entfernen Sie die Referenz dieser Dateien
  3. Fügen Sie die Dateien erneut zu Ihrem Projektbaum hinzu
  4. Öffnen Sie das Storyboard und erstellen Sie das Projekt neu

0

Aus Versehen habe ich meinen View Controller mit AVPlayerViewControllerstatt klassifiziert UIViewController. Indem Sie es UIViewControllerwieder normal spielen. Das sollte helfen.

Für mich hat keine Build-Bereinigung (normal und vollständig), das Entfernen abgeleiteter Datenordner und das Beenden von Xcode funktioniert.


0

Ich hatte das gleiche Problem, nachdem ich eine Klasse (mit einem xib verknüpft) kopiert hatte, um sie mit einer anderen Viewcontroller-Klasse (mit einem Storyboard verknüpft) wiederzuverwenden. Ich habe vergessen zu entfernen

override var nibName

und

override var nibBundle

Methoden.

Nachdem ich sie entfernt hatte, begannen meine Steckdosen zu arbeiten.


0

Ich sehe dich benutzen ViewController!? in ViewControllerKlasse Sie müssen verwenden -viewDidLoad, nicht -awakeFromNib , -awakeFromNibverwenden für UIViewKlasse



0

Wenn Sie zwei haben main.storyboardsund Änderungen an der falschen vornehmen, kann dies passieren. Dies kann immer dann passieren, wenn Sie eine Steckdose von einem unbegründeten Gerät aus anschließen storyboard.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.