2015-02-08 13 views
7

Viene visualizzato un messaggio di errore "Rilevato inaspettatamente nil durante lo scucamento di uno Optional" da Swift, con la classe di seguito. L'errore si verifica sulla linea:Trovato inaspettatamente nil durante lo srotolamento di un valore facoltativo swift

(cell.contentView.viewWithTag(1) as UILabel).text = object["firstName"] as? String 

Ho una classe cella personalizzato con 2 UILabels etichettato 1 e 2, le uscite sono impostate

import UIKit 
    import Foundation 

    class dictionaryTableViewController: UIViewController,  UITableViewDelegate, UITableViewDataSource{ 

    var objects = NSMutableArray() 
    var dataArray = [["firstName":"Debasis","lastName":"Das","email":"[email protected]"],["firstName":"John","lastName":"Doe","email":"[email protected]"],["firstName":"Jane","lastName":"Doe","email":"[email protected]"],["firstName":"Mary","lastName":"Jane","email":"[email protected]"]] 

    @IBOutlet 
    var tableView: UITableView! 

    var items: [String] = ["We", "Heart", "Swift"] 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "MyCell") 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return dataArray.count;//self.items.count; 
    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     //var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell 
     //cell.textLabel?.text = self.items[indexPath.row] 
     //return cell 
     let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as UITableViewCell 
     let object = dataArray[indexPath.row] as NSDictionary 
     (cell.contentView.viewWithTag(1) as UILabel).text = object["firstName"] as? String 
     (cell.contentView.viewWithTag(2) as UILabel).text = object["lastName"] as? String 
     return cell 
    } 

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

     println("You selected cell #\(indexPath.row)!") 

    } 

} 
+1

Credo che il problema è con 'viewWithTag (_ :)', che restituisce un '' UIView (opzionale 'UIView')?. Se è 'nil', l'accesso alla proprietà' text' provoca l'arresto anomalo. Prova a cambiare il codice in 'se lasci tag1 = cell.contentView.viewWithTag (1) come UILabel {...}' e mettici un breakpoint per vedere cosa succede. – Romain

risposta

20

Se si desidera utilizzare un layout di cella personalizzato, vorrei suggerire

  1. Sottoclasse UITableViewCell:

    // CustomTableViewCell.swift 
    
    import UIKit 
    
    class CustomTableViewCell: UITableViewCell { 
    
        @IBOutlet weak var firstNameLabel: UILabel! 
        @IBOutlet weak var lastNameLabel: UILabel! 
    
    } 
    
  2. Creare vista tabella in storyboard. Aggiungi il prototipo di cella a tableview nello storyboard. Progetta quel prototipo di cella (aggiungendo qualsiasi etichetta tu voglia).

  3. Specificare l'identificatore dello storyboard per il prototipo di cella come desiderato (MyCell nell'esempio).

    enter image description here

  4. specificare la classe base per il prototipo di cella di essere, in questo esempio, CustomTableViewCell:

    enter image description here

  5. collegare il IBOutlet riferimenti tra il prototipo di cella e la tua UITableViewCell sottoclasse .

    enter image description here

    Avviso i proiettili solidi a sinistra dei IBOutlet riferimenti. Ciò indica che la presa è stata collegata correttamente.

  6. Implementare cellForRowAtIndexPath nell'origine dati, ad es. a Swift 3:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell 
    
        let person = dataArray[indexPath.row] 
    
        cell.firstNameLabel.text = person["firstName"] 
        cell.lastNameLabel.text = person["lastName"] 
    
        return cell 
    } 
    

    O a Swift 2:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! CustomTableViewCell 
    
        let person = dataArray[indexPath.row] 
    
        cell.firstNameLabel.text = person["firstName"] 
        cell.lastNameLabel.text = person["lastName"] 
    
        return cell 
    } 
    
  7. nota, se si utilizza prototipi di cella, si fanno non desidera chiamare registerClass in viewDidLoad. Lo storyboard registrerà automaticamente la tua classe personalizzata con l'identificatore riutilizzato per te (a causa di ciò che hai fatto nei passaggi 3 e 4).

+0

Grazie, questa è la migliore risposta! – Jhonny

+0

Grazie, mi sono preso da quando sono abituato a creare xib per celle personalizzate: 7. Nota, se usi i prototipi di celle, non vuoi chiamare registerClass in viewDidLoad. Lo storyboard registrerà automaticamente la tua classe personalizzata con l'identificatore riutilizzato per te (a causa di ciò che hai fatto nei passaggi 3 e 4). –

+2

ho un errore "errore irreversibile: trovato inatteso nil mentre scartando un valore Opzionale" –

3

EDIT2: Questa soluzione è forse meglio per il vostro scopo. Con questo crei la tua classe per il tuo UITableViewCell e la usi con pattern di riutilizzo. I commenti sono nel codice:

class dictionaryTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{ 

    // The data 
    var dataArray = [["firstName":"Debasis","lastName":"Das","email":"[email protected]"],["firstName":"John","lastName":"Doe","email":"[email protected]"],["firstName":"Jane","lastName":"Doe","email":"[email protected]"],["firstName":"Mary","lastName":"Jane","email":"[email protected]"]] 

    // The outlet to your tableview in the ViewController in storyboard 
    @IBOutlet var tableView: UITableView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Create a nib for reusing 
     let nib = UINib(nibName: "MyCell", bundle: nil) 
     // Register the nib for reusing within the tableview with your reuseidentifier 
     tableView.registerNib(nib, forCellReuseIdentifier: "MyCell") 

     // Set delegate and datasource to self (you can do that in interface builder as well 
     tableView.delegate = self 
     tableView.dataSource = self 
    } 

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return dataArray.count; // return the number of datasets 
    } 

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

     // create a reusable cell with the reuse identifier you registered in viewDidLoad and cast it to MyCell 
     let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as MyCell 
     let object = dataArray[indexPath.row] as NSDictionary 

     // set the strings matching your array 
     cell.label1.text = object["firstName"] as? String 
     cell.label2.text = object["lastName"] as? String 

     // return the cell 
     return cell 

    } 

    // some example for the delegate 
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     println("You selected cell #\(indexPath.row)!") 
    } 


} 


// class for you own UITableViewCell 
// has own xib file 
class MyCell: UITableViewCell { 

    // two outlets representing two labels in the xib file 
    @IBOutlet private weak var label1: UILabel! 
    @IBOutlet private weak var label2: UILabel! 
} 

Per far funzionare tutto questo è necessario creare un XI ter-file con il nome giusto (in questo caso MyCell). Dovrebbe qualcosa di simile a questo:

enter image description here

E 'molto importante per impostare la classe di visualizzazione personalizzata e le prese.

------------------------------------- ALTRA SOLUZIONE ------- -------------------------------

EDIT: Come vedo, non si inizializza la propria classe " MyCell' ma la classe di Apple'UITableViewCell con il reuseIdentifier 'MyCell'. Questa è la soluzione per l'utilizzo di UITableViewCell:

La riga (cell.contentView.viewWithTag(1) as UILabel) non è solo un cast per una classe specifica, ma è anche scartata l'opzione (UIView). Lo fai in altri casi con '!'. Quindi il problema è: stai creando un'istanza di UITableViewCell, una classe creata da Apple. Vuoi ottenere sotto-visualizzazioni all'interno di quella vista con tag specifici. Come sai che Apple ha dato loro questi tag? Che cosa si vuole veramente è la creazione di un'istanza di UITableViewCell con uno stile particolare e impostare i valori delle textLabels come questo:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     // Create an instance of UITableViewCell. Style is .Subtitle but could be others as well 
     var cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as? UITableViewCell 
    let object = dataArray[indexPath.row] as NSDictionary 

    // set the strings matching your array 
    cell?.textLabel?.text = object["firstName"] as? String 
    cell?.detailTextLabel?.text = object["lastName"] as? String 

    // return the cell 
    return cell! 
    } 
+0

sta istanziando 'MyCell' - non la classe di Apple - quindi i suoi tag possono essere lì :) –

+0

Sì, ho impostato i miei tag, ma comunque ha funzionato così grazie! – Jhonny

+1

Ha impostato'MyCell' come un riutilizzatoreIdentificatore per la classe UITableViewCell in modo da inizializzare UITableViewCell. Se ha funzionato, controlla la risposta come corretta in modo che altre persone che stanno cercando questo problema possano vedere la risposta. – Ben

0

Tutto quello che dovevo fare era:

cell.subviews[0].subviews[0].viewWithTag(//your tag//) 
Problemi correlati