web-dev-qa-db-fra.com

UITableView dans Swift

J'ai du mal à comprendre ce qui ne va pas avec cet extrait de code. Cela fonctionne actuellement dans Objective-C, mais dans Swift, cela bloque juste sur la première ligne de la méthode. Il affiche un message d'erreur dans le journal de la console: Bad_Instruction.

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!  {
        var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell

        if (cell == nil) {
            cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
        }

        cell.textLabel.text = "TEXT"
        cell.detailTextLabel.text = "DETAIL TEXT"

        return cell
    }
60
DBoyer

Voir aussi la réponse de matt qui contient la seconde moitié de la solution

Trouvons une solution sans créer de sous-classes ou de plumes personnalisées

Le vrai problème réside dans le fait que Swift distingue les objets pouvant être vides (nil) des objets ne pouvant pas être vides. Si vous n'enregistrez pas de nib pour votre identifiant, alors dequeueReusableCellWithIdentifier peut renvoyer nil.

Cela signifie que nous devons déclarer la variable comme facultative:

var cell : UITableViewCell?

et nous devons lancer en utilisant as? pas as

//variable type is inferred
var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell

if cell == nil {
    cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")
}

// we know that cell is not empty now so we use ! to force unwrapping but you could also define cell as
// let cell = (tableView.dequeue... as? UITableViewCell) ?? UITableViewCell(style: ...)

cell!.textLabel.text = "Baking Soda"
cell!.detailTextLabel.text = "1/2 cup"

cell!.textLabel.text = "Hello World"

return cell
82
Sulthan

La réponse de Sulthan est intelligente, mais la vraie solution est: n'appelle pas dequeueReusableCellWithIdentifier. C'était votre erreur au début.

Cette méthode est complètement dépassée et je suis étonnée qu'elle ne soit pas officiellement déconseillée. aucun système compatible avec Swift (iOS 7 ou iOS 8) n’en a besoin pour quelque fin que ce soit.

Appelez plutôt la méthode moderne, dequeueReusableCellWithIdentifier:forIndexPath:. Cela a l’avantage que aucun option est impliqué; vous êtesgarantiqu'une cellule sera retournée. Tous les points d'interrogation et d'exclamation tombent, vous pouvez utiliser let au lieu de var car l'existence de la cellule est garantie et vous vivez dans un monde pratique et moderne.

Si vous n'utilisez pas de story-board, vous devez préalablement enregistrer la table pour cet identifiant, en enregistrant soit une classe, soit un nib. La méthode conventionnelle pour faire cela est viewDidLoad, ce qui correspond à la présence de la vue de table.

Voici un exemple d'utilisation d'une classe de cellule personnalisée:

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

// ...

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath) as MyCell
    // no "if" - the cell is guaranteed to exist
    // ... do stuff to the cell here ...
    cell.textLabel.text = // ... whatever
    // ...
    return cell
}

Mais si vous utilisez un storyboard (ce que la plupart des gens utilisent), vous n'avez même pas besoin d'enregistrer la vue de table dans viewDidLoad! Il suffit d'entrer l'identifiant de la cellule dans le storyboard et vous êtes prêt à utiliser dequeueReusableCellWithIdentifier:forIndexPath:.

63
matt

La réponse de @ Sulthan est parfaite. Une modification de commodité possible consisterait à convertir la cellule en UITableViewCell !, plutôt qu'en UITableViewCell!.

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as UITableViewCell!
    if !cell {
        cell = UITableViewCell(style:.Default, reuseIdentifier: "CELL")
    }
    // setup cell without force unwrapping it
    cell.textLabel.text = "Swift"
    return cell
}

Maintenant, vous pouvez modifier la variable de cellule sans forcer le dérouler à chaque fois. Soyez prudent lorsque vous utilisez des options implicitement non enveloppées. Vous devez être certain que la valeur à laquelle vous accédez a une valeur.

Pour plus d'informations, reportez-vous à la section "Options implicitement non emballées" de Le langage de programmation Swift .

18
aselvia

Essaye ça:

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    cell.textLabel.text = "\(indexPath.row)"

    return cell
}

Notez que vous devez vous enregistrer UITableViewCell et votre ID lors de la création pour instancier votre UITableView:

tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")
8
Oscar Swanros

Voici ce que j'ai écrit pour le faire fonctionner ...

Commencez par enregistrer la cellule de la vue tableau avec la vue tableau.

self.tableView.registerClass(MyTableViewCell.self, forCellReuseIdentifier: "Cell")

Puis configurez cellForRowAtIndexPath

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!  {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as MyTableViewCell

    cell.textLabel.text = "Cell Text"
    cell.detailTextLabel.text = "Cell Detail Text in Value 1 Style"

    return cell
}

J'ai ensuite défini une sous-classe de cellule personnalisée en bas du fichier (car c'est beaucoup plus facile maintenant)

class MyTableViewCell : UITableViewCell {

    init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: UITableViewCellStyle.Value1, reuseIdentifier: reuseIdentifier)
    }

}
8
DBoyer

Il y a quelques réponses ici, mais je pense qu'aucune d'entre elles n'est idéale, car après la déclaration, vous vous retrouvez avec un UITableViewCell facultatif, qui nécessite ensuite un cell!... dans toutes les déclarations. Je pense que c'est une meilleure approche (je peux confirmer cela compile sur Xcode 6.1):

var cell:UITableViewCell

if let c = tableView.dequeueReusableCellWithIdentifier("cell") as? UITableViewCell {
    cell = c
}
else {
    cell = UITableViewCell()
}
4
Chris Simpson

Voici un moyen simple de définir une cellule de tableau dans Swift 2:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let identifier = "cell"
    let cell = tableView.dequeueReusableCellWithIdentifier(identifier) ??
        UITableViewCell.init(style: UITableViewCellStyle.Default, reuseIdentifier: identifier)
    cell.textLabel!.text = "my text"
    return cell
}

Swift 3:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let identifier = "cell"
    let cell = tableView.dequeueReusableCell(withIdentifier: identifier) ??
        UITableViewCell(style: .default, reuseIdentifier: identifier)
    cell.textLabel!.text = "my text"
    return cell
}
4
david72

Eh bien, j'ai fait de cette façon:

Étapes pour UITableView using Swift :

  • Prenez UITableView in ViewController
  • Give Référencement des prises dans ViewController.Swift class 
  • Give Outlets dataSource & délégué à ViewController

Maintenant Swift code dans ViewController.Swift class:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var mTableView: UITableView!

    var items: [String] = ["Item 1","Item 2","Item 3", "Item 4", "Item 5"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.mTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

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

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:UITableViewCell = self.mTableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell

        cell.textLabel?.text = self.items[indexPath.row]
         println(self.items[indexPath.row])

        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        println("You have selected cell #\(indexPath.row)!")
    }
}

Maintenant il est temps de Lancez votre programme .

Terminé

2
Hiren Patel

En fait, dans le document TableView Guide et Sample Code du Apple, vous trouverez la phrase ci-dessous:

Si la méthode dequeueReusableCellWithIdentifier: demande une cellule définie dans un storyboard, elle retourne toujours une cellule valide. S'il n'y a pas de cellule recyclée en attente de réutilisation, la méthode en crée une nouvelle en utilisant les informations contenues dans le storyboard lui-même. Cela évite d'avoir à vérifier la valeur de retour pour nil et à créer une cellule manuellement.

Donc, nous pourrions simplement coder comme ceci:

var identifer: String = "myCell"
var cell = tableView.dequeueReusableCellWithIdentifier(identifer) as UITableViewCell
cell.textLabel.text = a[indexPath.row].name
cell.detailTextLabel.text = "detail"

Je pense que c'est un moyen approprié d'utiliser tableView

1
S.Captain

L'utilisation du mot clé "comme" effectuerait les deux étapes suivantes:
1.créer une valeur facultative qui enveloppe une variable de UITableViewCell;
2. Déballer la valeur optionnelle.

Alors, en faisant ça

var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Component") as UITableViewCell

vous obtiendrez une variable "ordinaire" de type UITableViewCell: cellule.En théorie, vous pouvez le faire.Mais la ligne suivante

if (cell == nil) {}

cela pose problème, car dans Swift, seule la valeur optionnelle peut être affectée de nil. 

Donc, pour résoudre ce problème, vous devez faire de la cellule une variable de type facultatif. juste comme ça:

var cell = tableView.dequeueReusableCellWithIdentifier("Component") as? UITableViewCell

en utilisant le mot clé "comme?" créerait une variable facultative, et celle-ci peut sans aucun doute être assignée avec nil.

1
li_shengdm

bro, s'il vous plaît jeter un oeil à l'exemple https://github.com/brotchie/SwiftTableView

0
haithngn

Pour le modèle de cellule: 

func tableView (tableView: UITableView !, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
 let myCell: youCell = youCell (style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cellule") 
 retourner myCell 
 } 
0
Lola

Je l'ai fait de la manière suivante: pour afficher detailTextLabel. valeur de texte

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

    let CellIdentifier: String = "cell"

    var cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as? UITableViewCell

    if cell == nil {
        cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: CellIdentifier)
    }

    //cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator

    // parse the value of records
    let dataRecord = self.paymentData[indexPath.row] as! NSDictionary

    let receiverName = dataRecord["receiver_name"] as! String
    let profession = dataRecord["profession"] as! String
    let dateCreated = dataRecord["date_created"] as! String
    let payAmount = dataRecord["pay_amount"] as! String

    println("payment \(payAmount)")
    cell!.textLabel?.text = "\(receiverName)\n\(profession)\n\(dateCreated)"
    cell!.detailTextLabel?.text = "$\(payAmount)"
    cell!.textLabel?.numberOfLines = 4

    return cell!

}// end tableview
0
Vinod Joshi

Pourquoi pas ça?

(veuillez supprimer si je ne suis pas dans le but ...)

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

    if let cell: UITableViewCell = theTableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as? UITableViewCell {
        // cell ok
    }else{
       // not ok
    }
}
0
Mk3d

J'ai parcouru vos codes et très probablement la cause de cet incident est que vous essayez de dactylographier une valeur facultative non affectée.

Considérons maintenant la ligne de code ci-dessous

var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell

Quand il n'y a pas de cellules dans la table, vous essayez toujours de transtyper en tant que UITableView.

La déclaration correcte devrait être 

var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") 

Vous pouvez utiliser l'instruction if else pour transtyper le typage des valeurs

0

UITableView Demo utilisant Playground

//: Playground - noun: a place where people can play

import UIKit
import PlaygroundSupport

class TableviewDemoDelegate:NSObject,UITableViewDataSource,UITableViewDelegate {


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath)

        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        }


        cell?.textLabel?.text = "Item \(indexPath.row+1)"

        return cell!
    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You have selected cell #\(indexPath.row)!")

    }
}

var tableView = UITableView(frame:CGRect(x: 0, y: 0, width: 320, height: 568), style: .plain)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

let delegate = TableviewDemoDelegate()
tableView.delegate = delegate
tableView.dataSource = delegate


PlaygroundPage.current.liveView = tableView
0
Kirit Vaghela