2017-02-11 19 views
0

私は、セルで行ではなくセクションで、合計5個のセルを持つカスタムUITableViewを持っています。各セルにはボタンがあり、5番目のセルのボタン(tableButton)に残りのタイトルと異なるタイトルを付けるようにします。Swift:cellForRowAtIndexPathの予期しない結果

これは私が以下のコードで正常に動作しています。最初の4セルは当初、コードごとに正しいタイトルを持っています。しかし、私は5番目のセル(期待されるタイトルを持つ)をスクロールし、最初のセルまでスクロールバックすると、最初のセルが5番目のセルに固有のタイトルに変更されました。

if cell.tableButton.tag == 4条件にprint文を追加し、5番目のセルまでスクロールするたびに印刷されます。

import UIKit 
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 

    @IBOutlet weak var tableView: UITableView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     tableView.delegate = self 
     tableView.dataSource = self 
    } 

    func numberOfSections(in tableView: UITableView) -> Int { 
     // #warning Incomplete implementation, return the number of sections 
     return 5 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     // #warning Incomplete implementation, return the number of rows 
     return 1 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell 
     cell.layer.borderWidth = 1 
     cell.layer.borderColor = UIColor.gray.cgColor 

     cell.tableButton.tag = indexPath.section 
     if indexPath.section == 4 { 
      cell.tableTitle.isHidden = true 
      cell.tableButton.setTitle("Special", for: .normal) 
     } else { 
      cell.tableButton.setTitle("Normal", for: .normal) 
     } 

     return cell 
    } 


    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 
     let returnedView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: 15)) 
     returnedView.backgroundColor = UIColor.groupTableViewBackground 

     return returnedView 
    } 

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 
     return 15 
    } 
} 

CustomCell.swift:

import UIKit 
class CustomCell: UITableViewCell { 

    @IBOutlet weak var tableButton: UIButton! 
    @IBOutlet weak var tableTitle: UILabel! 

    override func awakeFromNib() { 
     super.awakeFromNib() 
     // Initialization code 
    } 

    override func setSelected(_ selected: Bool, animated: Bool) { 
     super.setSelected(selected, animated: animated) 

     // Configure the view for the selected state 
    } 

} 
+1

おそらく、セルの状態が変更されている可能性があります。すべての場合に '.normal'を' [] 'に置き換えてください – penatheboss

+0

5つのセクションに5つのセルがありますか? – iAviator

+0

各セクションが1つの5つのセクション、合計5つのセル。 –

答えて

0

私はあなたがdequeReusableCellメソッドを使用しているので、これが起こると思います。あなたはテーブルビューに5つのセルしか持っていないので、私はそれ以上セルをデキューしないで、代わりにあなたのセルの新しいインスタンスを毎回作成するならば、それがあなたを傷つけるとは思わない。それはベストプラクティスではありませんが、簡単な解決策です!

+1

これは良いアプローチではありません。メモリ使用量が増えるためです。 – iAviator

+0

彼は 'prepareForReuse'メソッドを使うこともできますが、テーブルビューのセル数は静的で、5セルしかありません。 –

+0

セルの内容を設定するために 'prepareForReuse'を使うべきではありません。そのデリゲートメソッドはそのためのものではありません。 'tableView(_:cellForRowAt:)'のテーブルビューのデリゲートは、セルを再利用する際に常にすべてのコンテンツをリセットする必要があります。 –

0

シナリオを再作成しましたが、問題なく動作しています。私はそれがあなたのCustomCellの何かと関係しているかもしれないと思います。

ViewController.swift:

import UIKit 

class ViewController: UIViewController { 
    @IBOutlet weak var tableView: UITableView! 
} 

extension ViewController: UITableViewDataSource { 

    func numberOfSections(in tableView: UITableView) -> Int { 
     return 5 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return 1 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell 

     if indexPath.section == 4 { 
      cell.tableButton.setTitle("Special", for: .normal) 
     } else { 
      cell.tableButton.setTitle("Normal", for: .normal) 
     } 

     return cell 
    } 

} 

extension ViewController: UITableViewDelegate { 
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 
     return 250 
    } 
} 

CustomCell.swift:もちろん

import UIKit 

class CustomCell: UITableViewCell { 

    @IBOutlet weak var tableButton: UIButton! 

    override func prepareForReuse() { 
     tableButton.setTitle("RESET", for: .normal) 
    }  
} 

、このUITableViewの単純化された実装が、例にあなたのコードの多くを追加おそらく他の人があなたの問題を見たり再現したりすることができます。

+0

2つの異なるアクション(「特別」ボタン用と「通常」ボタン用のspecialActionおよびnormalAction)を追加した場合、prepareForResuseを使用して、最初のセルが実行中のときのようにセルを動作させる方法を教えてください両方のアクション! –

+0

私はそれを修正しました。心配しないでください。私はprepareForReuseのボタンからターゲットを削除しました! –

+0

メソッド 'PrepareForReuse'は、セルを新しいデータを設定するのではなく、再利用に適した状態にリセットするためのものです。最悪の場合でも、セルが依然として正しく動作しない場合は、 'UITableView'の' willDisplayCell'デリゲートメソッドでセルの内容を設定することができます。遅れて返信して申し訳ありません、_life_の間に入りました;) –

0

これは、あなたがtableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

を使用して、細胞を再利用しているので、あなたがここにいくつかのソリューションを持って、セルの再利用の問題のように見えます。最初は再利用しないで新しいものを作成することですが、より多くのメモリが使用されるためパフォーマンスが悪くなります。

このより良い解決策は、tableViewCellでの再利用を準備することです。カスタムtableViewCellのprepareForReuseメソッドをオーバーライドする必要があります。その方法では、ビューを初期状態(テキスト、アルファなど)に設定します。最初にsuper.prepareForReuseに電話することを忘れないでください。

+0

これは 'prepareForReuse'を使うのに非常に良いアプローチですが、これを動作させるための前提条件ではありません。 'UITableViewDelegate'は' CellForRowAtIndexPath'を呼び出す必要があります.'cellForRowAtIndexPath'はセルを取得し(newまたはdequeued)、 'tableButton'の値を変更します。 –

+0

ありがとう、このメソッドは、ボタンのタイトルをリセットするために機能します。これはどのようにボタンアクションにも使用できますか? 「特別な」ボタンに他のアクションと異なるアクションを与えると、最初のセルは実際には通常のアクションと特殊なアクションの両方を実行します。 –

+0

ボタンのアクションをどのように設定していますか?コードには表示されません –