web-dev-qa-db-ja.com

SwiftのUITableView

このコードスニペットの何が問題なのかを理解するのに苦労しています。これは現在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

また、ソリューションの後半を含む mattの答え も参照してください

カスタムサブクラスやペン先を作成せずに解決策を見つけましょう

本当の問題は、Swiftが空にできるオブジェクト(nil)と空にできないオブジェクトを区別するという事実にあります。識別子にペン先を登録しない場合、dequeueReusableCellWithIdentifiernilを返すことができます。

つまり、変数をオプションとして宣言する必要があります。

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

スルタンの答えは賢明ですが、本当の解決策は次のとおりです。dequeueReusableCellWithIdentifierを呼び出さないでください。それは最初の間違いでした。

このメソッドは完全に時代遅れであり、正式に廃止されていないことに驚いています。 Swift(iOS 7またはiOS 8)に対応できるシステムは、どんな目的でもそれを必要としません。

代わりに、最新のメソッドdequeueReusableCellWithIdentifier:forIndexPath:を呼び出します。これには、オプションが関係しないという利点があります。あなたはguaranteedセル​​が返されます。疑問符と感嘆符はすべて消えます。セルの存在が保証されているため、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の答えはまさにその通りです。便利な変更の1つは、セルを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のインスタンスを作成するときに、UITableViewとIDを登録する必要があることに注意してください。

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

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
}

スウィフト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
}
5
david72

ここにはいくつかの答えがありますが、私はそれらのどれも理想的ではないと思います。なぜなら、宣言の後、オプションのUITableViewCellになり、そのために宣言でcell!...が必要になるからです。私はこれがより良いアプローチだと思います(これはXcode 6.1でコンパイルすることを確認できます):

var cell:UITableViewCell

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

さて、私はこのようにした:

ITableViewを使用する手順Swiftを使用:

  • ITableView in ViewController
  • 参照コンセント in ViewController.Swift class
  • アウトレットを与えるdataSourcedelegate to ViewController

SwiftViewController.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ガイドドキュメントとサンプルコードには、次の文があります。

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

「as」キーワードを使用すると、次の2つのステップが実行されます。
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

キーワード「as?」を使用するオプション変数を作成しますが、これは間違いなくnilで割り当てることができます。

1
li_shengdm

仲間、サンプルを見てください https://github.com/brotchie/SwiftTableView

0
haithngn

セルテンプレートの場合:

func tableView(tableView:UITableView !, cellForRowAtIndexPath indexPath:NSIndexPath!)-> UITableViewCell! {
 let myCell:youCell = youCell(style:UITableViewCellStyle.Subtitle、reuseIdentifier: "cell")
 return 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ステートメントを使用して、保持する値を型キャストできます

0

Playgroundを使用した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