【问题标题】:Deleting rows inside tableview while using sender.tag使用 sender.tag 时删除 tableview 中的行
【发布时间】:2017-08-22 15:01:26
【问题描述】:

我的tableView cellForRowAtIndexPath 看起来像这样:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: CheckoutAppointmentCell.reuseIdentifier) as! CheckoutAppointmentCell
    cell.appointment = appointments[indexPath.row]
    cell.checkoutButton.tag = indexPath.row
    cell.checkoutButton.addTarget(self, action: #selector(checkoutButtonTapped), for: .touchUpInside)
    return cell
}

然后我从tableViewdataSource 中删除约会,如下所示:

func checkoutButtonTapped(sender: UIButton) {
    appointments.remove(at: sender.tag)
    print(sender.tag)
    //self.tableView.beginUpdates()
    self.tableView.deleteRows(at: [IndexPath(row:sender.tag, section: 0)], with: .automatic)
    //self.tableView.endUpdates()
}

我第一次删除约会时,它工作正常。 sender.tag 的值是它应该的值,并且正确的行已从 tableView 中删除。

删除第一行后,之后似乎删除了不正确的行。

我在调用deleteRows 后尝试调用reloadData(),但动画不再出现。 beginUpdates()endUpdates() 似乎也没有区别。

【问题讨论】:

  • 你这行的真正意思-:删除第一行后,之后似乎删除了不正确的行?你能解释一下它之后的作用吗?
  • 所以当我点击checkoutButton时,它会调用checkoutButtonTappedsender.tag 是第一次删除行时的正确值。例如,我点击第 2 行的 checkoutButton,sender.tag 为 2,因此从表视图中删除第 2 行。第一次删除后,sender.tag 不再是正确的值例如我可能与第 3 行交互,但 sender.tag 值将是第 4 行
  • 永远不要使用标签来表示索引路径。正如您在此处看到的,在表格视图中删除、插入或移动行会使所有剩余的行带有错误的索引路径标记。
  • @rmaddy 在使用表格视图删除行动画的同时,我还可以使用什么其他方法来正确更新表格视图数据源?

标签: ios swift uitableview


【解决方案1】:

使用标签来跟踪索引路径是一种常见但非常糟糕的做法。它在任何允许删除、插入或移动行的表视图中都会失败,因为剩余单元格现在具有无效标签,除非使用 reloadData 完全重新加载表视图。

不需要使用reloadData 来保持标签最新的更好解决方案是根据按钮的位置确定单元格按钮的indexPath

func checkoutButtonTapped(sender: UIButton) {
    let hitPoint = sender.convert(CGPoint.zero, to: tableView)
    if let indexPath = tableView.indexPathForRow(at: hitPoint) {
        // use indexPath to get needed data
    }
}

【讨论】:

  • hitPoint 的类型是 CGPoint。从自动完成我发现 indexPathForRow(at point: ) 。我猜它应该是这样的?
  • 糟糕。那是一个错字。答案是固定的。
【解决方案2】:

我不知道这是不是个好主意,但使用CallBack Closures 似乎也可以正常工作,因为使用标签不是个好主意。

正如@rmaddy 建议的一些观点,我相应地更新了答案。

CustomCell 类-:

  import UIKit

class testingCell: UITableViewCell {

    var deleteCallBack : ((testingCell)->())?// CallBack function

    @IBOutlet weak var parentlabel: UILabel!

    @IBAction func deleteButton(_ sender: UIButton) {
        // Call your closure 
        if let callBack = deleteCallBack{
            callBack(self)
        }
    }
    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
    }

}

控制器类-:

extension ViewController : UITableViewDelegate,UITableViewDataSource{

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}// Default is 1 if not implemented

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
    // return number of rows in section
    return data.count
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! testingCell
    cell.textLabel?.text = data[indexPath.row]

    cell.deleteCallBack = { [weak self] tableCell in
        //Print indexPath for selected Cell
        print(self?.dataTableView.indexPath(for: tableCell) as Any )

        if let selectedIndex  = self?.dataTableView.indexPath(for: tableCell) {
            // Print selected row
            print(selectedIndex.row)
            // delete row from array
            self?.data.remove(at: selectedIndex.row)
            // Get index row to be deleted from table
            let indePath = NSIndexPath(item: selectedIndex.row, section: selectedIndex.section)
            // delete row from table
            self?.dataTableView.deleteRows(at: [indePath as IndexPath], with: UITableViewRowAnimation.automatic)
        }

    }
    return cell
}


public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
    // Return cell height
    return 100
}

删除后确实打印出正确的索引。

【讨论】:

  • 1.不要强制解开deleteCallBack。如果未设置,应用程序将崩溃。 2. 您应该将单元格作为参数传递给回调。 3.不要调用reloadData删除一行。
猜你喜欢
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
  • 2016-12-25
  • 1970-01-01
相关资源
最近更新 更多