有没有一种简单的方法可以从UITableView中删除特定的自定义单元格?

时间:2020-03-20 04:56:47

标签: ios swift uitableview

我试图实例化表格视图中的空买方单元格(自定义单元格),然后让用户填充买方名称。当用户按下某行/单元格的删除按钮时,无论是否已填充该行的文本字段,都应删除相应的行/单元格。显然,我没有得到期望的行为。例如,当我按Delete Row0(其文本字段显示“ Buyer 0”)并且重新加载表格视图时,Buyer 0仍然存在,但是最后一个空的Buyer单元之一被删除了。

import UIKit

class EntryAlertViewController: UIViewController {

    //Fields/Table
    @IBOutlet weak var itemField: UITextField!
    @IBOutlet weak var priceField: UITextField!
    @IBOutlet weak var tableView: UITableView!

    //Visual Components
    @IBOutlet weak var mainView: UIView!
    @IBOutlet weak var titleView: UIView!
    @IBOutlet weak var splitItemButton: UIButton!
    @IBOutlet weak var cancelButton: UIButton!
    @IBOutlet weak var addItemButton: UIButton!

    //Commonly Used Objects/Variables
    var potentialBuyers: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        potentialBuyers.append("")
        tableView.dataSource = self
        tableView.register(UINib(nibName: "BuyerCell", bundle: nil), forCellReuseIdentifier: "ReusableCell")
    }

    override func viewWillAppear(_ animated: Bool) {
    }

    @IBAction func splitItemPressed(_ sender: UIButton) {
        potentialBuyers.append("")
        tableView.reloadData()
    }

}

这是tableview数据源和删除按钮委托。

extension EntryAlertViewController: UITableViewDataSource, DeleteButtonDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return potentialBuyers.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "ReusableCell", for: indexPath) as! BuyerCell
        cell.deleteButtonDelegate = self
        cell.indexPath = indexPath
        cell.nameField.text = cell.buyerName
        if potentialBuyers.count == 1 {
            cell.deleteButton.isHidden = true
        } else {
            cell.deleteButton.isHidden = false
        }
        return cell
    }


    func deletePressed(index: Int) {
        potentialBuyers.remove(at: index)
        tableView.reloadData()
    }


}

这是我的BuyerCell类,带有UITextFieldDelegate作为扩展。

import UIKit

protocol DeleteButtonDelegate {
    func deletePressed(index: Int)
}

class BuyerCell: UITableViewCell {

    @IBOutlet weak var deleteButton: UIButton!
    @IBOutlet weak var nameField: UITextField!

    var deleteButtonDelegate: DeleteButtonDelegate!
    var indexPath: IndexPath!
    var buyerName: String?

    override func awakeFromNib() {
        super.awakeFromNib()
        self.nameField.delegate = self
    }

    @IBAction func deletePressed(_ sender: UIButton) {
        //print the indexPath.row that this was pressed for
        print("delet pressed for \(indexPath.row)")
        self.deleteButtonDelegate?.deletePressed(index: indexPath.row)
    }

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

        // Configure the view for the selected state
    }

}

extension BuyerCell: UITextFieldDelegate {

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("textFieldDidBeginEditing")
        buyerName = nameField.text
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        print("textFieldDidEndEditing")
        buyerName = nameField.text
    }

}

2 个答案:

答案 0 :(得分:2)

您的问题出在这行

cell.nameField.text = cell.buyerName

单元格是从重用池中重用的,因此您不能依赖拥有任何特定状态或值的单元格。

您的买家名称必须来自您的数据模型数组。

类似

cell.nameField.text = self.potentialBuyers[indexPath.row]

仅删除一行时,重新加载整个tableview有点过多;只需删除相关行即可。

您还可以清理委派协议,以便该单元无需跟踪其indexPath-

protocol DeleteButtonDelegate {
    func deletePressed(in cell: UITableViewCell)
}

在您的单元格中:

@IBAction func deletePressed(_ sender: UIButton) {
    self.deleteButtonDelegate?.deletePressed(in: self)
}

在您的视图控制器中:

func deletePressed(in cell: UITableViewCell) {
    guard let indexPath = tableView.indexPath(for: cell) else {
        return
    }
    potentialBuyers.remove(at: indexPath.row)
    tableView.deleteRows(at:[indexPath], with: .automatic)
}

答案 1 :(得分:2)

您的代码中存在一个主要问题。您没有更新数据模型,因此当用户滚动时,单元格中的更改会丢失。

在Swift回调闭包中,

而不是相当 objective-c-ish 协议/委托更加方便和高效。您可以使用一个回调来更新模型和删除单元格。

替换BuyerCell单元格
class BuyerCell: UITableViewCell {

    @IBOutlet weak var deleteButton: UIButton!
    @IBOutlet weak var nameField: UITextField!

    var callback : ((UITableViewCell, String?) -> Void)?

    override func awakeFromNib() {
        super.awakeFromNib()
        self.nameField.delegate = self
    }

    @IBAction func deletePressed(_ sender: UIButton) {
        callback?(self, nil)
    }
}

extension BuyerCell: UITextFieldDelegate {

    func textFieldDidBeginEditing(_ textField: UITextField) {
        print("textFieldDidBeginEditing")
        callback?(self, nameField.text)
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        print("textFieldDidEndEditing")
        callback?(self, nameField.text)
    }
}

cellForRow中的控制器中分配回调并处理操作。如果对单元格进行重新排序,插入或删除,这些动作也可以可靠地工作。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "ReusableCell", for: indexPath) as! BuyerCell
    let buyerName = potentialBuyers[indexPath.row]
    cell.nameField.text = buyerName
    cell.callback = { [unowned self] cCell, cName in
        let currentIndexPath = tableView.indexPath(for: cCell)!
        if let name = cName {
             self.potentialBuyers[currentIndexPath.row] = name
        } else {
            self.potentialBuyers.remove(at: currentIndexPath.row)
            tableView.deleteRows(at: [currentIndexPath], with: .fade)
        }
    }
    cell.deleteButton.isHidden = potentialBuyers.count == 1
    return cell
}