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
}
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
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:
.
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 .
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")
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)
}
}
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()
}
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
}
Eh bien, j'ai fait de cette façon:
Étapes pour UITableView using Swift :
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é
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
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.
bro, s'il vous plaît jeter un oeil à l'exemple https://github.com/brotchie/SwiftTableView
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 }
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
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
}
}
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
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