webentwicklung-frage-antwort-db.com.de

UITableView in Swift

Ich habe Schwierigkeiten, herauszufinden, was mit diesem Code-Snippet nicht stimmt. Dies funktioniert derzeit in Objective-C, aber in Swift stürzt dies nur in der ersten Zeile der Methode ab. Es zeigt eine Fehlermeldung im Konsolenprotokoll an: 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

Siehe auch die Antwort von matt die die zweite Hälfte der Lösung enthält

Lassen Sie uns eine Lösung finden, ohne benutzerdefinierte Unterklassen oder Spitzen erstellen zu müssen

Das eigentliche Problem besteht in der Tatsache, dass Swift zwischen Objekten, die leer sein können (nil), und Objekten, die nicht leer sein können, unterscheidet. Wenn Sie für Ihre Kennung keine Spitze registrieren, kann dequeueReusableCellWithIdentifiernil zurückgeben.

Das heißt, wir müssen die Variable als optional deklarieren:

var cell : UITableViewCell?

und wir müssen mit as? nicht as arbeiten

//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

Sulthans Antwort ist klug, aber die wirkliche Lösung ist: rufe nicht dequeueReusableCellWithIdentifier auf. Das war zu Beginn dein Fehler.

Diese Methode ist völlig veraltet, und ich bin überrascht, dass sie nicht formell abgelehnt wurde. Kein System, das Swift aufnehmen kann (iOS 7 oder iOS 8), benötigt es zu jedem Zweck.

Rufen Sie stattdessen die moderne Methode dequeueReusableCellWithIdentifier:forIndexPath: auf. Dies hat den Vorteil, dass keine Optionals beteiligt sind; Sie sindgarantiert, dass eine Zelle zurückgegeben wird. Alle Fragezeichen und Ausrufezeichen fallen weg. Sie können let anstelle von var verwenden, da die Existenz der Zelle garantiert ist und Sie in einer bequemen, modernen Welt leben.

Wenn Sie kein Storyboard verwenden, müssen Sie zuvor die Tabelle für diese Kennung registrieren, indem Sie entweder eine Klasse oder eine Feder registrieren. Der übliche Ort dafür ist viewDidLoad, was so früh ist, als die Tabellenansicht überhaupt existiert.

Hier ein Beispiel mit einer benutzerdefinierten Zellklasse:

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
}

Wenn Sie jedoch ein Storyboard verwenden (was die meisten Leute tun), müssen Sie die Tabellenansicht nicht in viewDidLoad registrieren! Geben Sie einfach die Zellkennung in das Storyboard ein und Sie können mit dequeueReusableCellWithIdentifier:forIndexPath: fortfahren.

63
matt

@ Sulthans Antwort ist genau richtig. Eine mögliche Änderung der Bequemlichkeit wäre, die Zelle als UITableViewCell! Und nicht als UITableViewCell zu konvertieren.

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
}

Jetzt können Sie die Zellenvariable ändern, ohne sie jedes Mal zwangsweise auspacken zu müssen. Seien Sie vorsichtig, wenn Sie implizit nicht verpackte Optionals verwenden. Sie müssen sicher sein, dass der Wert, auf den Sie zugreifen, einen Wert hat.

Weitere Informationen finden Sie im Abschnitt "Implizit nicht verpackte Optionals" in The Swift Programming Language .

18
aselvia

Versuche dies:

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

    return cell
}

Beachten Sie, dass Sie UITableViewCell und ID beim Erstellen der Instantiierung Ihrer UITableView registrieren sollten:

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

Hier ist, was ich geschrieben habe, damit es funktioniert ...

Registrieren Sie zuerst die Tabellensichtzelle mit der Tabellensicht

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

Konfigurieren Sie anschließend 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
}

Ich habe dann eine benutzerdefinierte Zellunterklasse definiert, die sich am unteren Ende der Datei befindet (da sie jetzt viel einfacher ist).

class MyTableViewCell : UITableViewCell {

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

}
8
DBoyer

Hier gibt es ein paar Antworten, aber ich denke nicht, dass eine davon ideal ist, denn nach der Deklaration erhalten Sie eine optionale UITableViewCell, die dann in allen Deklarationen einen cell!... benötigt. Ich denke, dass dies ein besserer Ansatz ist (ich kann dies unter Xcode 6.1 kompilieren):

var cell:UITableViewCell

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

In Swift 2 können Sie eine einfache Tabellenzelle definieren:

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

Nun, ich habe diesen Weg gemacht:

Schritte für UITableView mit Swift :

  • UITableView in ViewController übernehmen
  • Geben Sie Verweise auf Ausgänge in ViewController.Swift class 
  • Outlets dataSource & delegieren an ViewController

Jetzt Swift Code in 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)!")
    }
}

Jetzt ist es Zeit, Ihr Programm auszuführen .

Erledigt

2
Hiren Patel

Im Apple TableView Guide-Dokument und im Beispielcode finden Sie den folgenden Satz:

Wenn die Methode dequeueReusableCellWithIdentifier: nach einer Zelle fragt, die in einem Storyboard definiert ist, gibt die Methode immer eine gültige Zelle zurück. Wenn keine recycelte Zelle auf die Wiederverwendung wartet, erstellt die Methode eine neue Zelle, die die Informationen im Storyboard selbst verwendet. Dadurch müssen Sie den Rückgabewert für nil nicht überprüfen und manuell eine Zelle erstellen.

Also könnten wir einfach so schreiben:

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

Ich denke, dass dies eine geeignete Möglichkeit ist, TableView zu verwenden

1
S.Captain

Die Verwendung des Schlüsselworts "as" führt die folgenden zwei Schritte aus:
1.Erstellen eines optionalen Werts, der eine Variable von UITableViewCell umgibt;
2.Entfernen des optionalen Werts.

Also, indem Sie dies tun

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

sie würden eine UITableViewCell-Variable vom Typ "plain" erhalten: cell.Theoretisch ist das in Ordnung. Aber die nächste Zeile

if (cell == nil) {}

macht Ärger, weil in Swift nur der optionale Wert mit nil zugewiesen werden kann. 

Um dieses Problem zu lösen, müssen Sie für die Zelle eine Variable des optionalen Typs festlegen. genau wie dieser:

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

mit dem Stichwort "wie?" würde eine optionale Variable erstellen, und diese kann zweifellos mit nil zugewiesen werden.

1
li_shengdm

bro, bitte schau dir das Beispiel an https://github.com/brotchie/SwiftTableView

0
haithngn

Für Zellenvorlage: 

func tableView (tableView: UITableView !, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
 let myCell: youCell = youCell (Stil: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell") 
 myCell zurückgeben 
 } 
0
Lola

Ich habe folgendes getan: detailTextLabel anzeigen. Textwert

 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

Warum nicht das?

(bitte streichen, wenn ich nicht im Ziel bin ...)

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

Ich habe Ihre Codes durchgesehen und der Grund für den Absturz ist höchstwahrscheinlich, dass Sie versuchen, einen optionalen Wert einzugeben, der nicht zugewiesen wurde

Betrachten Sie nun die folgende Codezeile

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

Wenn sich in der Tableview keine Zellen befinden, versuchen Sie immer noch, UITableView als Typ zu konvertieren

Die richtige Aussage sollte sein 

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

Sie können die if else -Anweisung verwenden, um für Werte, die gelten, zu konvertieren

0

UITableView Demo mit 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