快速汇总UITableView单元格上的值

时间:2019-06-22 16:19:53

标签: ios swift uitableview

我在视图控制器中也有一个TableView,在UILabel中也有一个UIViewController。一切都能很好地显示,但是我正在努力实现某些目标,而我无法简单地将其背后的逻辑。

tableview单元格具有一个UILabel,该单元格上具有Int值,这些数字现在变化了,如何在tableView单元格中获取Label上的数字总和并显示在视图控制器中的Label上。

我尝试在UIView控制器中创建一个变量并将此值添加到t,但由于无法将这个数字加在一起而无法执行操作

有关如何执行此操作的任何帮助。谢谢

var total: Double?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        switch indexPath.section {
        case 0:
            let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! BrokageCheckoutCell
            cell.configure()
            total = Double("\(cell.subPrice.text!)")
            cell.selectionStyle = .none
            return cell
        case 1:
            let cell = tableView.dequeueReusableCell(withIdentifier: cellId2, for: indexPath) as! OtherCheckoutCell
            cell.configure()
            cell.selectionStyle = .none
            return cell
        default: break
        }
        return UITableViewCell()
    }

2 个答案:

答案 0 :(得分:1)

您问:

  

如何获取tableView单元格中Label上的数字总和并显示在视图控制器中的Label上

简而言之,您没有。表格视图单元格中的标签(属于“视图”的一部分)不是我们的数据源。它仅用于显示各个字符串。

例如,假设您的应用程序要累加100个项目,但该应用程序的表格视图一次只能显示12行。为了提高内存和性能,iOS将重用滚动到视图外的单元格,以显示滚动到视图中的新行的内容。但这意味着您不能说“将这100个单元格中所有标签的内容相加”,因为没有100个单元格;只有十二个。

您的应用应改为引用其“模型”,即cellForRowAt用于确定在给定的表格视图单元格中显示什么的结构(例如,数组)。因此,如果要累加总数,则应累加该数组中的值,而不要完全引用单元格。

并且如果您的单元格具有允许修改数据的控件,则该单元格应启动模型的更新。然后,计算总计(对数组中的值求和)的过程仍然有效。

因此,我们来看一个示例:

  1. 您应该有一个包含要求和的数字的模型。您的示例尚不清楚,因此我将创建一个示例,其中每个表行均包含名称,单价和数量:

    struct Item {
        let name: String
        let unitPrice: Decimal
        var quantity: Decimal
    }
    

    在此示例中,任何给定行的总计将是数量乘以单价。所有行的总计将是所有这些乘积的总和。

  2. 然后,您的视图控制器可能会有一个用于其模型的数组:

    var items: [Item] = ...
    
  3. 然后,当您要更新总计标签时,只需一种方法即可计算出每一行总计的数量乘以总计价格,然后对这些值求和以计算总计。然后它将相应地更新总计文本字段:

    private extension ViewController {
        func updateTotal() {
            let total = items
                .map { $0.quantity * $0.unitPrice }
                .reduce(0, +)
    
            totalLabel.text = totalFormatter.string(for: total)
        }
    }
    

    注意,我不是从单元格中检索这些数字(因为这些数字可能会被重复使用),而是从模型中检索所有我需要的数据。

  4. 但是,这里的关键是,例如,如果您的单元格允许用户更改这些值之一,则需要一种机制来更新表视图控制器的模型。我们将为此使用协议:

    protocol ItemCellDelegate: class {
        func cell(_ cell: ItemCell, didUpdateQuantity quantity: Decimal)
    }
    
    class ItemCell: UITableViewCell {
        @IBOutlet weak var nameLabel: UILabel!
        @IBOutlet weak var quantityTextField: UITextField!
        @IBOutlet weak var unitPriceLabel: UILabel!
    
        static let quantityFormatter: NumberFormatter = ...
        static let priceFormatter: NumberFormatter = ...
    
        weak var delegate: ItemCellDelegate?
    }
    

    很明显,当您配置单元格时,视图控制器将指定用于更新文本字段(或其他内容)的委托:

    // MARK: Public methods
    
    extension ItemCell {
        func configure(name: String, quantity: Decimal, unitPrice: Decimal, delegate: ItemCellDelegate) {
            self.delegate = delegate
    
            nameLabel.text = name
            quantityTextField.text = ItemCell.quantityFormatter.string(for: quantity)
            unitPriceLabel.text = ItemCell.priceFormatter.string(for: unitPrice)
        }
    }
    

    ItemCell得到更新时,它仅调用委托:

    // MARK: Private methods
    
    private extension ItemCell {
        @IBAction func didUpdateQuantity(_ sender: UITextField) {
            var quantity: Decimal?
    
            if let text = sender.text, let value = ItemCell.quantityFormatter.number(from: text) {
                quantity = value.decimalValue
            }
    
            delegate?.cell(self, didUpdateQuantity: quantity ?? 0)
        }
    }
    

    然后,当视图控制器配置单元格时,它将提供自己作为委托:

    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return items.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell
            let item = items[indexPath.row]
            cell.configure(name: item.name, quantity: item.quantity, unitPrice: item.unitPrice, delegate: self)
            return cell
        }
    }
    

    当然,视图控制器将遵循该协议以接受对文本字段的更新并更新模型:

    extension ViewController: ItemCellDelegate {
        func cell(_ cell: ItemCell, didUpdateQuantity quantity: Decimal) {
            guard let indexPath = tableView.indexPath(for: cell) else { return }
    
            items[indexPath.row].quantity = quantity
    
            updateTotal()
        }
    }
    

    而且,正如您所看到的,如果可以,在更新模型之后,它也可以自动更新总数。

这里的关键是我们永远不要将单元格用作存放数据的地方。这些单元格仅用于(a)显示数据和(b)通知视图控制器是否需要了解任何更新。

我们努力明确区分职责,其中“视图”用于显示当前与屏幕上的控件并进行交互,而“模型”包含我们的所有数据。

答案 1 :(得分:0)

执行此操作的通常方法是拥有单元格的委托,并使ViewController成为该委托。每当单元格的值发生变化时,就将该值通过委托发送,以便视图控制器可以将所有这些值加起来。

那是快速的方法。

执行此操作的更好方法是为单元格提供一个数据源,以跟踪值。这样做会更好,因为随着单元格在屏幕上滚动和滚动,数据源可以跟踪值并在该索引路径再次可见时恢复它们。

由于数据源知道值是什么,所以对它们求和很简单。