UITableView в Swift

Я изо всех сил пытаюсь понять, что случилось с этим фрагментом кода. В настоящее время это работает в Objective-C, но в Swift это просто падает в первой строке метода. В журнале консоли отображается сообщение об ошибке: 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
    }

Ответ 1

Также см. матовый ответ, который содержит вторую половину решения

Найти решение без создания пользовательских подклассов или nibs

Реальная проблема заключается в том, что Swift различает объекты, которые могут быть пустыми (nil), и объекты, которые не могут быть пустыми. Если вы не зарегистрируете нить для своего идентификатора, тогда dequeueReusableCellWithIdentifier может вернуть nil.

Это означает, что мы должны объявить переменную как необязательную:

var cell : UITableViewCell?

и нам нужно использовать as? not 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

Ответ 2

Ответ Sulthan умный, но реальное решение: не вызывайте dequeueReusableCellWithIdentifier. Это была ваша ошибка с самого начала.

Этот метод полностью устарел, и я удивлен, что он официально не устарел; никакая система, которая может вместить Swift (iOS 7 или iOS 8), не нуждается ни в каких целях.

Вместо этого вызовите современный метод dequeueReusableCellWithIdentifier:forIndexPath:. Это имеет то преимущество, что никакие опции не задействованы; вы гарантировали, что ячейка будет возвращена. Все вопросительные знаки и восклицательные знаки отпадают, вы можете использовать let вместо var, потому что существование ячейки гарантировано, и вы живете в удобном современном мире.

Вы должны, если вы не используете раскадровку, заранее зарегистрируйте таблицу для этого идентификатора, зарегистрировав либо класс, либо нить. Обычное место для этого - viewDidLoad, которое уже существует в виде таблицы.

Вот пример использования пользовательского класса ячеек:

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
}

Но если вы используете раскадровку (что делает большинство людей), вам даже не нужно регистрировать представление таблицы в viewDidLoad! Просто введите идентификатор ячейки в раскадровку, и вы можете пойти с dequeueReusableCellWithIdentifier:forIndexPath:.

Ответ 3

@Ответ Sulthan - это место. Одна из возможных модификаций удобства заключается в том, чтобы скрыть ячейку как UITableViewCell!, а не 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
}

Теперь вы можете изменить переменную ячейки без принудительной разворачивания ее каждый раз. Соблюдайте осторожность при использовании неявно развернутых опций. Вы должны быть уверены, что значение, к которому вы обращаетесь, имеет значение.

Для получения дополнительной информации см. раздел "Неявно отключенные опции" на языке Swift Programming.

Ответ 4

Попробуйте следующее:

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

    return cell
}

Обратите внимание, что вы должны зарегистрировать UITableViewCell и ID при создании экземпляра UITableView:

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

Ответ 5

Вот что я написал, чтобы заставить его работать...

Сначала зарегистрируйте ячейку таблицы со списком таблиц

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

Затем настройте 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
}

Затем я определил пользовательский подкласс ячеек в нижней части файла (так как теперь его стало намного проще)

class MyTableViewCell : UITableViewCell {

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

}

Ответ 6

Здесь несколько ответов, но я не думаю, что любой из них идеален, потому что после объявления вы получаете опциональный UITableViewCell, который тогда нуждается в cell!... в любых объявлениях. Я думаю, что это лучший подход (я могу подтвердить этот компилятор на Xcode 6.1):

var cell:UITableViewCell

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

Ответ 7

Вот простой способ определить ячейку таблицы в 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
}

Ответ 8

Ну, я сделал так:

Шаги для UITableView с помощью Swift:

  • Возьмите UITableView в ViewController
  • Дайте Referuting Outlets в классе ViewController.swift
  • Выдать dataSource и делегировать на ViewController

Теперь Swift в классе ViewController.swift:

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)!")
    }
}

Теперь пришло время Запустить программу.

Готово

Ответ 9

Фактически в документе Apple TableView Guide и в примере кода вы найдете следующее предложение:

Если метод dequeueReusableCellWithIdentifier: запрашивает ячейку, определенную в раскадровке, метод всегда возвращает действительную ячейку. Если нет повторно используемой ячейки, ожидающей повторного использования, метод создает новый, используя информацию в самой раскадровки. Это устраняет необходимость проверки возвращаемого значения для nil и создания ячейки вручную.

Итак, мы могли бы просто написать следующее:

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

Я думаю, что это подходящий способ использования tableView

Ответ 10

Использование ключевого слова "as" выполняет следующие два действия:
1.Создание необязательного значения, которое обертывает переменную UITableViewCell; 2.unupping необязательное значение.

Итак, сделав это

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

вы получили бы "обычную" переменную типа UITableViewCell: cell. Теоретически это нормально делать. Но следующая строка

if (cell == nil) {}

создает проблемы, потому что в swift может быть назначено только необязательное значение с помощью nil.

Итак, чтобы решить эту проблему, вы должны сделать ячейку переменной необязательного типа. просто так:

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

используя ключевое слово "as?" создаст необязательную переменную, и это, без сомнения, может быть назначено с помощью nil.

Ответ 11

Для шаблона ячейки:

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

Ответ 13

Почему не это?

(пожалуйста, удалите, если я не в цель...)

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

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

Ответ 14

Я сделал следующее: чтобы показать detailTextLabel. текстовое значение

 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

Ответ 15

UITableView Demo с использованием игровой площадки

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

Ответ 16

Я просмотрел ваши коды и, скорее всего, причина сбоя в том, что вы пытаетесь придумать необязательное значение, которое не назначено

Теперь рассмотрим строку кода ниже

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

Когда в представлении таблицы нет ячеек, вы все еще пытаетесь ввести тип в качестве UITableView. Когда компилятор пытается определить значение nil, которое вы сталкиваетесь с этой проблемой

Правильный оператор должен быть

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

Вы можете использовать if else для typecast для значений, которые содержат

Ответ 17

Попробуйте этот код

var cell:CustomTableViewCell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell") as CustomTableViewCell
cell.cellTitle.text="vijay"

https://github.com/iappvk/TableView-Swift