2016-04-05 9 views
2

Es tut mir leid, noch eine andere "gefunden nil Unwrapping optional in TableViewCell" Posting, aber nach Stunden des Debuggens und lesen andere solche Beiträge hier, ich bin immer noch fest. Ich denke, ich habe alle üblichen Fehler behandelt, kann aber immer noch nicht alles zum Laufen bringen.xcode 7 Swift gefunden nil beim Auspacken optional in einer Tabellenansicht Zelle

Als Ausgangspunkt funktioniert alles einwandfrei, solange ich die Standardbezeichnung in der Zelle verwende, auf die mit "cell.textLabel! .text = mystring" verwiesen wird. Und ich habe einen anderen Fall, in dem ich die Prototypzelle mit einem Bild und einem Etikett anpasste, und das hat auch gut funktioniert.

Im aktuellen Fall habe ich einen normalen UIViewController, mit einigen anderen Ansichten und einem UITableView eingebettet. Der normale UIViewController wird als Delegat für die Zellen festgelegt.

Hier ist der Code SettingsCell.swift. Ziemlich einfach. Der kleine Punkt auf der linken Seite des Outlet in xcode ist durchgehend und zeigt an, dass der Ausgang ordnungsgemäß mit dem CellTwo-Etikett an meiner Prototyp-Tischzelle verbunden ist.

class SettingsCell: UITableViewCell { 

    @IBOutlet weak var CellTwo: UILabel! 

    override init(style: UITableViewCellStyle, reuseIdentifier reuseID: String?) { 
    super.init(style: style, reuseIdentifier: reuseID) 
    } 

    required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
    } 
} 

Im entsprechenden SettingsVC.swift View-Controller, hier ist der dequeueCell Code, der auf den Versuch, um den cell.CellTwo Wert der Null Fehler nimmt.

Die Zellen werden in der Tabellenansicht ordnungsgemäß angezeigt, es wird jedoch nur der StandardtextLabel.txt angezeigt, der Teil von UILabel ist. Mein benutzerdefiniertes Label wird nicht angezeigt.

func tableView(
    tv: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    let cell = tv.dequeueReusableCellWithIdentifier("SettingsCell") as! SettingsCell 
    let row = indexPath.row 

    cell.textLabel!.text = SettingsNames[row] 
    // the commented out line below crashes on a nil unwrapped optional 
    // cell.CellTwo!.text = "Blah" 
    if let b = cell.CellTwo { 
     b.text = "Blah" 
    } 
    return cell 
    } 

Mit dem kleinen „lassen b =“ optional unwrap nil Schutz, ist die App nicht abstürze, aber mein zweites Etikett entweder bekommt nicht gesetzt. Betrachten wir schließlich die Registrierung der Klasse.

Viele Beispiele existieren im Netz (ohne Prototypen zu verwenden), wo Sie die Klasse registrieren, und ich habe das vorher erfolgreich getan. Und ich habe ein Beispiel gemacht, wo ich eine benutzerdefinierte Prototyp-Zelle gebaut habe, und die hat auch gut funktioniert. Aber ... ich denke, all diese Beispiele verwendeten einen UITableViewController, keinen normalen UIViewController + Embedded UITableView. Vielleicht hat das etwas damit zu tun.

Wie auch immer, hier ist der init/viewDidLoad-Code im UIViewController, der das UITableView enthält. Wie Sie aus dem Code entnehmen können, beansprucht der UIViewController die Verantwortung für die Datenquelle und die Delegierten, und tatsächlich erscheinen die Tabellenzeilen und funktionieren gut.

Ich habe versucht Registrierung in beide Richtungen - ohne die Coderegistrierung und mit der Code-Registrierungszeile. Aber es macht überhaupt keinen Unterschied - mein Code stürzt immer noch auf dem Null-Verweis auf mein benutzerdefiniertes Label in der Zelle ab.

class SettingsVC: UIViewController, UITableViewDataSource, UITableViewDelegate { 

    override func viewDidLoad() { 
    super.viewDidLoad() 
    SettingsTV.dataSource = self 
    SettingsTV.delegate = self 
    // I tried with this line in and out, no difference, the crash still happens 
    //SettingsTV.registerClass(SettingsCell.self, forCellReuseIdentifier: "SettingsCell") 
    SettingsTV.estimatedRowHeight = 70 
    } 

Es ist wie meine benutzerdefinierte Label irgendwie nicht erstellt oder initialisiert wird. Aber ich kann es nicht erklären. Irgendwelche Ideen? Danke

+0

Haben Sie in Ihrem Storyboard die Klasse Ihrer Prototypzelle in 'SettingsCell' geändert? Versuchen Sie auch, die Steckdose zu trennen und wieder anzuschließen, manchmal brechen sie. Versuchen Sie schließlich, Ihre Zelle in 'cellForRowAtIndexPath' folgendermaßen zu erstellen:' let cell = tableView.dequeueReusableCellWithIdentifier ("SettingsCell", forIndexPath: indexPath) ' – Wes

+0

Vielen Dank für Ihre Hilfe. Ich bestätige: Ja, die Storyboard-Prototypzelle ist an die SettingsCell-Klasse gebunden. Ich habe die Steckdose wieder getrennt/wieder angeschlossen (ich stimme zu, manchmal gehen sie wackelig und brechen). Und ich habe meine "tv" local var in tableView.dequeue geändert, wie Sie es gewünscht haben. Leider keine Änderung der Ergebnisse. Wenn ich versuche, cell.CellTwo einen Wert zuzuweisen, dauert es einen Null-Fehler. Es sieht so aus, als ob ich die "entschaufelte" (frisch erstellte) Zelle in eine SettingsCell umwandeln würde, in der Erwartung, dass die Zelle tatsächlich eine SettingsCell ist, wobei der Ausgang den eigentlichen Label-Speicher ersetzt. Aber es ist nicht wirklich da. – Kevin

+0

Haben Sie die Wiederverwendungs-ID im Storyboard festgelegt? –

Antwort

0

Die Antwort zu meinem Problem war in der Initialisierung der SettingsCell, die im ersten Block des Codes oben gezeigt wird. Diese Initialisierungssequenz wurde von einem Beispiel kopiert, das gut funktionierte, aber das STORYBOARD NICHT BENUTZTE. Stattdessen beschränkte sich dieses Beispiel auf die Verwendung der Standardfelder textLabel.text in der UITableViewCell-Definition.

Um das Problem zu lösen, ging ich einfach weiter durch meine Beispiele, um das Problem in Beispielen zu rekonstruieren, die bereits funktionierten. Hier ist der Schlüssel.

Wenn Sie das Storyboard mit einer Prototypzelle verwenden, kann die Tabellenzelleninitialisierung nicht wie der erste Block in diesem Beitrag aussehen !!Dieser Stil funktioniert nur für Nicht-Storyboard-Zellen.

Stattdessen sollte es wie folgt aussehen. Beachten Sie, dass ich den Standardcode auskommentiert habe, den xcode beim Erstellen in die Datei einfügt. Sie können also grundsätzlich eine leere Klasse für die Zelle haben, solange Sie Plätze für die Outlets haben.

 class SettingsCell: UITableViewCell { 

     @IBOutlet weak var XXXLabel: UILabel! 
     @IBOutlet weak var CellTwo: UILabel! 

     //  override func awakeFromNib() { 
     //  super.awakeFromNib() 
     //  // Initialization code 
     //  } 
     // 
     //  override func setSelected(selected: Bool, animated: Bool) { 
     //  super.setSelected(selected, animated: animated) 
     // 
     //  // Configure the view for the selected state 
     //  } 
    } 

Eine zweite Sache, die war, zeigte sich, daß die beiden Etiketten auf dem Storyboard an jedem Ende des ANY-irgendeine Größe Storyboard platziert wurden. Und meine Constraints legen die rechte Hand von der Kante des simulierten Geräts ab. Ich habe zufällig das Gerät im Simulator gedreht, und presto! Da war das zweite Label. Ich sollte den Previewer häufiger verwenden. :-)

0

Haben Sie versucht, Ihre benutzerdefinierte Zelle in einem separaten XIB zu definieren, anstatt Prototypzellen in der Tabellenansicht zu verwenden? Es ist ziemlich genau das Gleiche wie das, was Sie getan haben, aber es hat nur eine andere XIB-Datei aus dem Storyboard. So erstellen Sie das XIB:

Datei -> Neue Datei -> iOS -> Benutzeroberfläche -> Leer Ziehen Sie ein UITableViewCell zum XIB und passen Sie es entsprechend an. Legen Sie seine Klasse SettingsCell und Draht, die Etiketten auf, etc ... zu Ihrer SettingsCell Klasse

Dann in Ihrem VC registrieren Sie es dies wie:

let nibName = UINib(nibName: "SettingsCell", bundle:nil) 
self.SettingsTV.registerNib(nibName, forCellReuseIdentifier: "SettingsCell") 
+0

Hallo, vielen Dank für Ihren Vorschlag. Tut mir leid zu sagen, ich weiß nichts über NIBs oder XIBs ... Und ich habe herausgefunden, was hier vor sich geht und habe es hier dokumentiert. – Kevin

+0

Großartig, dass alles funktioniert hat. Alles Gute in deiner Entwicklung. Prost – rach

0

Ein weiterer Teil der Antwort in den Inhalt ist der Der NSCoder benötigte einen Init-Block, der oben in diesem Beitrag angezeigt wird. Dieser Block wurde von einem Arbeitsbeispiel kopiert, das KEINE Storyboard-Prototypzelle verwendet hat. Daher habe ich oft einen fatalen Fehler gemacht, als ich das mit meiner Prototyp-Tabellenansichtszelle versuchte.

Hier ist, was dieser Block SOLL (muss) aussehen, wenn Sie eine Prototyp-Zelle verwenden. Die erforderlichen NSCoder muss den super.init nennen, etwa so:

 required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     //fatalError("init(coder:) has not been implemented") 
     } 

Es ist seltsam, dass, wenn Xcode die NSCoder Ausgabe Auto-fixiert durch eine Vorlage Injektion NSCoder init erforderlich? Funktion injiziert es eine, die mit Prototypzellen brechen wird. Warum nicht die Zeile super.init (..) anstelle der fatalen Fehlerzeile hinzufügen? Wahrscheinlich gibt es einen Grund, aber keinen, den ich sehen kann.

Wie auch immer, all das funktioniert jetzt für mich, sogar mit einem Prototyp Storyboard-Tabellenansicht. Also ich denke, das sind alle Fragen/Probleme, die für dieses Problem gelöst sind.

Verwandte Themen