it-roy-ru.com

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
    }
60
DBoyer

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

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

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

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

var cell : UITableViewCell?

и мы должны привести, используя as?, а не 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

Ответ Султана умный, но реальное решение: not call 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:.

63
matt

@ 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
}

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

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

18
aselvia

Попробуй это:

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")
8
Oscar Swanros

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

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

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

}
8
DBoyer

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

var cell:UITableViewCell

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

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

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

Шаги для UITableView использование Swift :

  • Взять UITableView в ViewController
  • Give Ссылки на магазины in ViewController.Swift class 
  • Give Outlets источник данных & делегировать к 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)!")
    }
}

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

Готово

2
Hiren Patel

На самом деле в документе 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

1
S.Captain

Использование ключевого слова «как» сделает следующие два шага:
1.создание необязательного значения, которое оборачивает переменную UITableViewCell;
2. Оборачивание необязательного значения.

Итак, делая это

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

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

if (cell == nil) {}

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

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

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

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

1
li_shengdm

брат, пожалуйста, посмотрите на образец https://github.com/brotchie/SwiftTableView

0
haithngn

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

func tableView (tableView: UITableView !, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
 let myCell: youCell = youCell (стиль: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell") 
 вернуть myCell 
 } 
0
Lola

Я сделал следующим образом: показать 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
0
Vinod Joshi

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

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

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

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

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

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

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

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

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

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

0
Suryanarayan Sahu

UITableView Демо с использованием детской площадки

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